数値を丸める — Math.round / floor / ceil / trunc と toFixed

4つの丸め方の違い、負の数で結果が分かれる理由、toFixed が文字列を返すこと、そして 1.005 が 1.00 になる理由と、その回避策も効かない場面までを実行して確かめます。

実行して検証済み処理系Node 22.22.3対応ES1難易度●●○○○目安9更新

丸め方は4つあります。負の数で結果が分かれます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
2.5 3 2 3 2 -2.5 -2 -3 -2 -2 2.4 2 2 3 2 -2.4 -2 -3 -2 -2
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
-2 -3 3 3
関数 やること -2.5
Math.round() より大きいほうへ+0.5 して切り捨て) -2
Math.floor() 小さいほうへ(下へ) -3
Math.ceil() 大きいほうへ(上へ) -2
Math.trunc() 0へ(小数を捨てる) -2

Math.round() は四捨五入ではない

-2.5-2 になります。 四捨五入なら -3 のはずです。

Math.round() は「0.5 を足して切り捨てる」という決まりです。 正の数では四捨五入と同じ結果になりますが、負の数ではずれます。

「絶対値で四捨五入」したいなら、自分で書きます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1234.57 string
javascript
console.log((1.5).toFixed(1) + 1);
1.51

「四捨五入」と言われたら、負の数をどうするか先に確かめてください。

toFixed() は文字列を返す

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1.00 1.01 1.02
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1 100.49999999999999

数値ではありません。 そのまま足すと文字列の連結になります。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
10.05 10.05 1010
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1,234,567.891 1,234,568 ¥1,235

計算に戻すなら Number() を通してください。 → 文字列を数値に変換する

1.0051.00 になる

いちばん有名な落とし穴です。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
true true false 9007199254740991 true false
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
true

3つとも切り上がっていません

理由は toFixed() の不具合ではありません。1.005 という数がそもそも存在しないからです。 二進法で書けないので、実際には 1.005 よりわずかに小さい数が入っています。 → なぜ 0.1 + 0.2 は 0.30000000000000004 になるのか

よくある回避策も効かない

「100倍して丸めて戻す」という書き方が知られています。これも同じ理由で外れます。

1.005 * 100100.49999999999999 なので、Math.round()100 にします。 掛けた時点でずれています。

roundTo(1.234567, 3) のような普通の値では正しく働きます。効かないのは、二進法で表せない値がちょうど境界に来たときです。

どうすればよいか

お金や数量のように「ずれてはいけない数」は、小数で持たないでください。

最小単位(円・グラム・ミリ秒)の整数で持ち、表示するときだけ割る。 これがいちばん確実です。

表示だけが目的なら toFixed() で十分です。1円のずれが問題になる計算に使わない、 というだけの話です。

桁区切りや通貨は Intl に任せる

自分で3桁ごとにカンマを入れないでください。 言語ごとの区切り方は Intl が知っています。

ロケールを省くと環境の設定で結果が変わります。必ず 'ja-JP' のように書いてください。

整数かどうかを確かめる

3.03 と同じ数です。JavaScript に整数型と小数型の区別はありません

安全に扱える整数は 2^53 - 1 までです。それを超えると、隣の数と区別できなくなります。

大きな識別子は BigInt か文字列で持ってください。

まとめ

  • Math.round() は四捨五入ではない。 -2.5-2
  • 0へ寄せるなら Math.trunc()、下へなら floor()、上へなら ceil()
  • toFixed()文字列を返す。足すと連結になる
  • (1.005).toFixed(2)1.00 その数がそもそも無いから
  • 100倍して丸める回避策も、同じ理由で外れることがある
  • ずれてはいけない数は、最小単位の整数で持つ
  • 桁区切りと通貨は toLocaleString()。ロケールを必ず書く

この記事の根拠

  1. Math.round — ECMAScript® 2026 Language Specificationtc39.es
  2. Number.prototype.toFixed — ECMAScript® 2026 Language Specificationtc39.es
  3. IEEE 754-2019 — IEEE Standard for Floating-Point Arithmeticstandards.ieee.org

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)