数値を切り上げ、切り捨て、または最近接値に丸める方法

異なる丸めモードを使用してJavaScriptで小数を書式設定する際の丸め方を制御する

はじめに

表示用に数値を書式設定する際、小数値を丸める必要がよくあります。$2.567の価格は$2.57にする必要があります。3.891メートルの測定値は4メートルと表示されるかもしれません。これらの数値の丸め方は、精度、ユーザーの期待、ビジネスロジックに影響します。

状況によって異なる丸め戦略が必要です。製品に対して十分な料金を請求するために切り上げが必要な場合もあります。予算内に収めるために切り捨てが必要な場合もあります。最も多いのは、精度を維持するために最近接値に丸める場合です。

JavaScriptはIntl.NumberFormat APIを通じて9種類の異なる丸めモードを提供しています。これらのモードは、数値が2つの可能な値の間に位置する場合の丸め方を制御します。このレッスンでは、最も一般的な3つの丸めモードを説明し、その他のモードをいつ使用するかを示します。

JavaScriptがデフォルトで数値を丸める方法

丸めモードを指定せずに数値を書式設定すると、JavaScriptはhalfExpandと呼ばれる戦略を使用します。このモードは値を最も近い可能な値に丸め、数値が2つの値のちょうど中間に位置する場合は、ゼロから離れる方向に丸めます。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0
});

console.log(formatter.format(2.4));
// Output: "2"

console.log(formatter.format(2.5));
// Output: "3"

console.log(formatter.format(2.6));
// Output: "3"

値2.4は3よりも2に近いため、2に切り捨てられます。値2.6は2よりも3に近いため、3に切り上げられます。値2.5は2と3のちょうど中間に位置するため、halfExpandモードはゼロから離れる方向に丸めて3にします。

このデフォルトの動作は、ほとんどの人が学校で学び、日常的な計算で期待するものと一致します。多くの計算において丸め誤差を均等に分散させるため、汎用的な数値書式設定に適しています。

ゼロから離れるとは何を意味するかを理解する

「ゼロから離れる」という表現は、2つの可能な値のちょうど中間に位置する数値の丸め方向を示します。正の数の場合、ゼロから離れる方向に丸めるとは切り上げを意味します。負の数の場合、ゼロから離れる方向に丸めるとは絶対値が大きくなる方向への切り捨てを意味します。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0
});

console.log(formatter.format(2.5));
// Output: "3"

console.log(formatter.format(-2.5));
// Output: "-3"

2.5と-2.5はどちらもゼロから離れる方向に丸められます。2.5の場合、ゼロから離れるとは正の無限大方向を意味し、3になります。-2.5の場合、ゼロから離れるとは負の無限大方向を意味し、-3になります。どちらの場合も絶対値が増加します。

ceilで切り上げる

ceil丸めモードは常に正の無限大方向に丸めます。正の数の場合は切り上げを意味し、負の数の場合はゼロ方向への丸めを意味します。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "ceil"
});

console.log(formatter.format(2.1));
// Output: "3"

console.log(formatter.format(2.9));
// Output: "3"

console.log(formatter.format(-2.1));
// Output: "-2"

console.log(formatter.format(-2.9));
// Output: "-2"

このモードは、数値が必要以上に小さくならないようにする必要がある場合に便利です。例えば、箱に2.3個のアイテムが入ると計算した場合、3つの箱が必要です。タスクに1.1日かかると計算した場合、2日間の計画が必要です。

const boxFormatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "ceil"
});

const itemsPerBox = 5;
const totalItems = 12;
const boxesNeeded = totalItems / itemsPerBox;

console.log(boxFormatter.format(boxesNeeded));
// Output: "3"

計算結果は2.4箱ですが、箱の端数を注文することはできません。切り上げることで十分な容量を確保できます。

floorで切り捨てる

floor丸めモードは常に負の無限大方向に丸めます。正の数の場合は切り捨てを意味し、負の数の場合はゼロから離れる方向への丸めを意味します。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "floor"
});

console.log(formatter.format(2.1));
// Output: "2"

console.log(formatter.format(2.9));
// Output: "2"

console.log(formatter.format(-2.1));
// Output: "-3"

console.log(formatter.format(-2.9));
// Output: "-3"

このモードは、控えめな見積もりが必要な場合や制限内に収めたい場合に便利です。例えば、予算が$100.87ある場合、誤って使いすぎないように$100と表示することがあります。

const budgetFormatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  maximumFractionDigits: 0,
  roundingMode: "floor"
});

const availableBudget = 100.87;

console.log(budgetFormatter.format(availableBudget));
// Output: "$100"

切り捨てにより、表示される金額は常に実際の予算で達成可能な金額になります。

halfExpandによる最近接への丸め

halfExpandはデフォルトですが、コード内で意図を明確にするために明示的に指定できます。このモードは最も近い値に丸め、中間値の場合はゼロから離れる方向に丸めます。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 1,
  roundingMode: "halfExpand"
});

console.log(formatter.format(2.14));
// Output: "2.1"

console.log(formatter.format(2.15));
// Output: "2.2"

console.log(formatter.format(2.16));
// Output: "2.2"

値2.14は2.1に近いため、2.1に丸められます。値2.16は2.2に近いため、2.2に丸められます。値2.15はちょうど中間にあるため、ゼロから離れる方向に丸めて2.2になります。

このモードは、多数の計算における総丸め誤差を最小化するため、ほとんどの数値フォーマットタスクに適しています。各中間値はゼロの正側または負側になる確率が等しいため、丸め方向は時間の経過とともにバランスが取れます。

丸めモードと小数桁数の組み合わせ

丸めモードは小数桁数の設定と連携して最終的な出力を制御します。maximumFractionDigitsオプションは表示される小数点以下の桁数を決定し、roundingModeは表現可能な数値の間にある値の処理方法を決定します。

const ceilFormatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
  roundingMode: "ceil"
});

console.log(ceilFormatter.format(10.001));
// Output: "$10.01"

console.log(ceilFormatter.format(10.999));
// Output: "$11.00"

小数点以下2桁の場合、10.001は10.00または10.01のいずれかに丸める必要があります。ceilモードは切り上げて10.01になります。値10.999は11.00に切り上げられます。

truncによるゼロ方向への丸め

trunc丸めモードはゼロ方向に丸めます。つまり、数値の小数部分を削除します。正の数の場合は切り捨て、負の数の場合は切り上げになります。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "trunc"
});

console.log(formatter.format(2.1));
// Output: "2"

console.log(formatter.format(2.9));
// Output: "2"

console.log(formatter.format(-2.1));
// Output: "-2"

console.log(formatter.format(-2.9));
// Output: "-2"

このモードは小数部分を実質的に切り捨てます。丸めの目的で小数値を考慮せずに、数値の整数部分のみを表示したい場合に便利です。

expandによるゼロから離れる方向への丸め

expand丸めモードはゼロから離れる方向に丸めます。正の数の場合は切り上げ、負の数の場合はより大きな絶対値に切り捨てます。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "expand"
});

console.log(formatter.format(2.1));
// Output: "3"

console.log(formatter.format(2.9));
// Output: "3"

console.log(formatter.format(-2.1));
// Output: "-3"

console.log(formatter.format(-2.9));
// Output: "-3"

このモードは、丸めが常に数値の絶対値を増加させることを保証します。過小評価よりも精度を優先する方向で保守的にしたい財務コンテキストで有用です。

中間値丸めモードの理解

halfで始まる5つのモードはすべて最も近い値に丸めますが、正確な中間値の処理方法が異なります。これらのモードは、値が2つの表現可能な数値の正確に中間に位置する場合のタイブレーク動作を細かく制御できます。

halfCeilモードは中間値を正の無限大に向かって丸めます。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "halfCeil"
});

console.log(formatter.format(2.5));
// Output: "3"

console.log(formatter.format(-2.5));
// Output: "-2"

halfFloorモードは中間値を負の無限大に向かって丸めます。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "halfFloor"
});

console.log(formatter.format(2.5));
// Output: "2"

console.log(formatter.format(-2.5));
// Output: "-3"

halfTruncモードは中間値をゼロに向かって丸めます。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "halfTrunc"
});

console.log(formatter.format(2.5));
// Output: "2"

console.log(formatter.format(-2.5));
// Output: "-2"

halfEvenモードは中間値を最も近い偶数に丸めます。このモードは財務計算における偏りを減らすため、銀行家の丸めと呼ばれることもあります。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 0,
  roundingMode: "halfEven"
});

console.log(formatter.format(2.5));
// Output: "2"

console.log(formatter.format(3.5));
// Output: "4"

console.log(formatter.format(4.5));
// Output: "4"

2.5は2が偶数であるため2に丸められます。3.5は4が偶数であるため4に丸められます。4.5も4が偶数であるため4に丸められます。

アプリケーションに適した丸めモードの選択

選択する丸めモードは、ビジネス要件と表示するデータの性質によって異なります。異なるコンテキストには異なる戦略が必要です。

十分性を確保する必要がある場合はceilを使用してください。キャパシティプランニング、在庫数、時間見積もりでは、十分なリソースを保証するために切り上げが必要になることがよくあります。

制限内に収める必要がある場合はfloorを使用してください。予算表示、割当追跡、割引計算では、利用可能なリソースを超えないように切り捨てが必要になることがよくあります。

精度が重要であるものの極端な精密さが求められない一般的な表示にはhalfExpandを使用してください。これが理由があってデフォルトとなっており、ほとんどの数値フォーマットタスクで適切に機能します。

累積的な丸め誤差を最小限に抑える必要がある金融計算にはhalfEvenを使用してください。このモードは、多数の計算において丸め誤差が一方向に偏らないことを保証します。

小数部分に丸めロジックを適用せずに数値の整数部分のみを表示したい場合はtruncを使用してください。

通貨フォーマットでの丸めモードの使用

丸めモードは通貨フォーマットと自然に連携します。企業によって通貨値の丸め方に関するルールは異なり、roundingModeオプションを使用することでそれらのルールを実装できます。

const retailPrice = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
  roundingMode: "ceil"
});

const wholesalePrice = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
  roundingMode: "floor"
});

const calculatedPrice = 19.874;

console.log(retailPrice.format(calculatedPrice));
// Output: "$19.88"

console.log(wholesalePrice.format(calculatedPrice));
// Output: "$19.87"

小売業者は収益性を確保するために価格を切り上げる一方、卸売業者は競争力を維持するために切り捨てる場合があります。同じ計算価格でも、丸めモードにエンコードされたビジネスルールに基づいて異なる表示値が生成されます。