Code Fix

中級

0.1 + 0.2 === 0.3 がfalseになる理由と直し方

浮動小数点数は2進数で表現されるため、0.1や0.2のような10進の小数を正確に表せません。演算結果はごくわずかな誤差を含み、===での比較は失敗します。

なぜエラーが出ないのか

出力: false
(エラーなし)
JavaScriptは何も報告しません。文法として正しいためです
出力: false
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  const price = 0.1 + 0.2;
 2  console.log(price === 0.3                         );
                                   ^
出力: false期待: true (エラーにはなりません)

0.1と0.2は2進数の浮動小数点数として正確に表せないため、加算結果はわずかに0.3からずれます。厳密な===ではなく、誤差の範囲で比較する必要があります。

直し方: price === 0.3 を Math.abs(price - 0.3) < Number.EPSILON にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  const total = 1 - 0.9;
 2  console.log(total === 0.1                         );
                                   ^
出力: false期待: true (エラーにはなりません)

1 - 0.9も浮動小数点の誤差で0.1と厳密には一致しません。減算でも加算と同じ問題が起こります。

直し方: total === 0.1 を Math.abs(total - 0.1) < Number.EPSILON にします。

この問題を解いてみる →

パターン3

 1  const sum = 0.1 * 3;
 2  console.log(sum === 0.3                         );
                                  ^
出力: false期待: true (エラーにはなりません)

掛け算でも同じ誤差が生じます。0.1 * 3は0.30000000000000004になり、0.3とは===で一致しません。

直し方: sum === 0.3 を Math.abs(sum - 0.3) < Number.EPSILON にします。

この問題を解いてみる →

パターン4

 1  const value = 0.2 + 0.4;
 2  console.log(value === 0.6                         );
                                   ^
出力: false期待: true (エラーにはなりません)

0.2と0.4の加算でも同じ誤差が生じます。===での比較はほぼ確実に失敗します。

直し方: value === 0.6 を Math.abs(value - 0.6) < Number.EPSILON にします。

この問題を解いてみる →

パターン5

 1  const remainder = 0.3 - 0.2;
 2  console.log(remainder === 0.1                         );
                                     ^
出力: false期待: true (エラーにはなりません)

引き算でも同じ問題が起きます。誤差の範囲で比較するのが唯一の確実な方法です。

直し方: remainder === 0.1 を Math.abs(remainder - 0.1) < Number.EPSILON にします。

この問題を解いてみる →

よくある誤解

「小数の計算は正確なはず」という前提はJavaScriptに限らずほとんどの言語の浮動小数点数に当てはまりません。厳密な一致ではなく、Number.EPSILONのような小さな許容誤差の範囲で比較する必要があります。

実務での勘所

Number.EPSILONを使った比較(Math.abs(a - b) < Number.EPSILON)は、1前後の小さな数同士を比べる場面ではよく機能しますが、絶対的な万能薬ではありません。非常に大きな数同士(1e20同士など)や非常に小さな数同士を比較する場合、その桁数において意味のある誤差の大きさがEPSILON(約2.22×10のマイナス16乗)とは桁違いになるため、比較先の数値の大きさに応じてスケールさせた許容誤差を使う必要があります。単純にEPSILONをコピペするだけでは不十分な場面があることを覚えておくと安全です。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)