HOWTO · JavaScript

JavaScript の整数除算

JavaScript では Math.trunc または Math.floor を選び、負の値でも商と余りを正しく計算します。

このページの内容

JavaScript には // の整数除算演算子はありません。通常の Number 値では、商の小数部をゼロ方向に捨てるなら Math.trunc(dividend / divisor) を使い、余りには % を使います。切り捨てではなく下方向への丸めが必要なときだけ Math.floor() を選びます。負の値では結果が異なるため、近道を選ぶ前に規則を決めることが重要です。

結論:切り捨てか床関数の意味を選ぶ

整数除算には二つの意味があります。切り捨ての商は小数桁を取り除くので、Math.trunc(-13 / 5) は -2 です。床関数の商は負の無限大方向へ丸めるため、Math.floor(-13 / 5) は -3 です。正の入力ではどちらも 2 になり、負の値が本番に入るまで違いが隠れることがあります。

符号付きの量を商と符号付き余りに分ける処理には切り捨てを使います。ゼロ始まりのバケットや循環インデックスのように商を常に下へ丸める処理には床除算を使います。JavaScript の % は常に非負の数学的モジュロではなく余りを返し、符号は被除数に従います。MDN は余り演算子と数学的モジュロを区別しています。

推奨する Number の商と余り

有限の Number 入力では、Math.trunc と % により商と余りの関係を明示できます。これは通常の整数除算に推奨される方法です。計算前に除数がゼロでないことを確認してください。ゼロでない Number を符号付きゼロで割ると符号付き Infinity になり、0 / 0 は NaN、除数ゼロの Number の余りも NaN です。ECMAScript 仕様がこれらのケースを定義しています。

const dividend = 13;
const divisor = 5;

console.log(`quotient: ${Math.trunc(dividend / divisor)}`);
console.log(`remainder: ${dividend % divisor}`);
quotient: 2
remainder: 3

余りは結果の検証にも使えます。整数入力では dividend は divisor * quotient + remainder と等しくなります。この関係は検証に便利ですが、商を Math.trunc で計算する方が、間接的に導くよりも意図した丸め規則を明確に表せます。

負のオペランドと符号付き余り

負のオペランドは切り捨てと床関数の意味を分ける境界です。-13 / 5 では切り捨ては -2、床除算は -3 です。非ゼロの余りでは JavaScript が被除数の符号を保つため、% の結果は -3 になります。負の入力で失敗するわけではなく、異なる問いに答えるだけです。

const dividend = -13;
const divisor = 5;

console.log(`truncating quotient: ${Math.trunc(dividend / divisor)}`);
console.log(`floor quotient: ${Math.floor(dividend / divisor)}`);
console.log(`remainder: ${dividend % divisor}`);
truncating quotient: -2
floor quotient: -3
remainder: -3

床除算またはモジュロが必要な場合

正の除数に対して非負のモジュロが必要なら、% がすでにその動作をするとは考えず余りを正規化します。両方の値が同じ床除算の規則を使うよう Math.floor と組み合わせます。次の例は五項目の循環には適しますが、すべての商と余りの処理に適するわけではありません。

const dividend = -13;
const divisor = 5;
const quotient = Math.floor(dividend / divisor);
const modulo = ((dividend % divisor) + divisor) % divisor;

console.log(`floor quotient: ${quotient}`);
console.log(`non-negative modulo: ${modulo}`);
floor quotient: -3
non-negative modulo: 2

この正規化は除数が正であることを仮定します。除数が負になり得る場合は、必要な規則を別に定義してテストしてください。

BigInt による大きな正確な整数

Number は IEEE-754 の浮動小数点値を使います。安全な整数範囲を超えるとすべての整数を正確に表せないため、Number の商や余りに頼る前に Number.isSafeInteger で入力を検証してください。より大きな正確な整数には一貫して BigInt を使います。BigInt の除算はゼロ方向に切り捨て、余りも同じ符号付き余りの考え方に従います。

const dividend = 13n;
const divisor = 5n;

console.log(`quotient: ${dividend / divisor}`);
console.log(`remainder: ${dividend % divisor}`);

try {
  13n / 0n;
} catch (error) {
  console.log(`zero divisor: ${error.name}`);
}

try {
  13n / 5;
} catch (error) {
  console.log(`mixed types: ${error.name}`);
}
quotient: 2
remainder: 3
zero divisor: RangeError
mixed types: TypeError

Number と BigInt のオペランドを混在させず、演算前に意図して変換してください。BigInt のゼロ除数は RangeError を投げ、Number のゼロ除数とは異なります。したがって両方で入力検証が有用です。MDN は BigInt の除算、型混在エラー、ゼロ除数を説明しています。

ビット演算の強制変換や parseInt を使わない理由

~~value や value | 0 を短い切り捨ての慣用句として見かけることがあります。ビット演算子は符号付き 32 ビット整数へ強制変換し、範囲外の値を変えてしまうため、一般的な整数除算には避けてください。parseInt は文字列の解析用であり、数値丸め API ではありません。MDN は Math.trunc とビット変換の違いを説明しています。比較例は 32 ビット境界と正当な文字列解析を示します。

const value = 2 ** 32 + 1;

console.log(`Math.trunc: ${Math.trunc(value)}`);
console.log(`~~value: ${~~value}`);
console.log(`value | 0: ${value | 0}`);
console.log(`parseInt("13.8", 10): ${parseInt("13.8", 10)}`);
Math.trunc: 4294967297
~~value: 1
value | 0: 1
parseInt("13.8", 10): 13

数値の Number 値には Math.trunc を使い、入力が解析すべきテキストの場合だけ parseInt(text, 10) を使います。どちらの近道も浮動小数点精度を直しません。大きな整数で正確な演算が必要なら BigInt を使ってください。

判断の要約と制限

通常の JavaScript 整数除算には Math.trunc(a / b) と a % b を使います。床関数の意味が必要なときだけ正規化したモジュロと Math.floor(a / b) を使います。正確な大きな整数には BigInt を使い、ゼロ除数を拒否し、一つの演算で BigInt と Number を混在させません。ビット強制変換と parseInt は別の問題を解くため、汎用的な代替として避けてください。