ほとんどのプログラミング言語で 0.1 + 0.2 を表示すると 0.30000000000000004 になります。故障ではなく、コンピューターが実数を保存する仕組みによるものです。このガイドでは、SciKey をはじめ多くの数値計算ソフトが使う IEEE 754 倍精度形式、その限界が結果にどう現れるか、そして電卓がそれをどう扱っているかを説明します。
1. IEEE 754 倍精度
倍精度(binary64)は 64 ビットを使います。
| 部分 | ビット数 | 役割 |
|---|---|---|
| 符号 | 1 | 正か負か |
| 指数 | 11 | 2 の何乗か |
| 仮数 | 52 | 有効数字(先頭の隠れた 1 を含めて実質 53 ビット) |
有効 53 ビットは 10 進数でおよそ 15~17 桁に相当します。表せる最大値は約 1.797×10³⁰⁸ で、1 とその次の倍精度数との差(計算機イプシロン)は 2⁻⁵² ≈ 2.22×10⁻¹⁶ です。
2. 0.1 は2進数で正確に表せない
1/3 = 0.333… が 10 進数で終わらないのと同じように、1/10 は2進数で終わりません。0.1 = 0.0001100110011…₂ と無限に繰り返します。これが 53 ビットに丸められるので、実際に保存される値は
0.1000000000000000055511151231257827…
です。0.2 もわずかに大きく保存されます。その和は両方の誤差を引き継いで 0.3000000000000000444… となり、0.3 を保存した倍精度数(0.2999999999999999888…)とは別の倍精度数になります。そのため、この和を区別できる最短の 10 進表記は 0.30000000000000004 になります。
同じ理由で 0.1×3 も 0.30000000000000004 です。0.5、0.25、0.375 のように分母が 2 のべき乗である小数は2進数で正確に表せるので、誤差はありません。
3. それでも電卓で 0.3 と見える理由
SciKey は内部の値をそのまま表示せず、設定した有効桁数(既定 12 桁)に丸めて表示します。0.30000000000000004 を 12 桁に丸めると 0.300000000000、つまり 0.3 です。誤差は 17 桁目にあり、表示までは届きません。
実物の関数電卓も同じ仕組みで、一般に内部で 15 桁前後を計算し 10 桁を表示することで、末尾のわずかな誤差を表示の段階で隠しています。変わるのは表示だけなので、保存されている値は 0.30000000000000004 のままです。それを使って計算を続けても誤差はふつう 10⁻¹⁶ 程度で、実用上は問題になりません。
4. sin(π) はなぜ 0 にならないのか
RAD モードの sin(π) は本来ちょうど 0 のはずです。しかし π は無理数で、π に最も近い倍精度数は真の値より約 1.22×10⁻¹⁶ 小さくなっています。π の近くで sin の傾きは −1 なので、sin(倍精度の π) ≈ 1.2246×10⁻¹⁶ になります。sin 自体は正確に計算されています。入力がもともと正確な π ではなかったのです。
SciKey は次の規則で補正しています。
- DEG と GRAD モードでは、引数を 360°(400 gon)で正確に還元し、90° の倍数では正確な値を返します:
sin(180)= 0、cos(90)= 0、tan(90)は定義されないのでエラーを返します。 - RAD モードでは、引数が π の整数倍と相対誤差 10⁻¹³ 以内で一致すれば sin は 0 を返し、π/2 の奇数倍と一致すれば cos は 0 を返し、tan はエラーを返します。
そのため SciKey では sin(π) が 0 と表示されます。この補正は π の倍数の近くでだけ働き、ほかの計算には影響しません。
5. 大きな数: 階乗とオーバーフロー
階乗は急激に大きくなります。170! ≈ 7.25741561531×10³⁰⁶ はまだ倍精度に収まりますが、171! は約 1.24×10³⁰⁹ で、最大値 1.797×10³⁰⁸ を超えます。そのため SciKey の n! は 0~170 の整数を受け付け、171! はオーバーフローエラーを返します。
実際には、大きな階乗はたいてい比の中に現れます。組合せ C(200, 3) は 200!/(3!·197!) ですが、nCr(200, 3) = 1313400 なら巨大な途中の値を経ずに直接計算できます。確率の計算では、対数をとって足し合わせるのもよく使われる方法です。
6. 整数の限界: 2⁵³
有効 53 ビットなので、2⁵³ = 9007199254740992 までのすべての整数は正確です。それを超えると、倍精度数は整数を飛び飛びにしか表せません。2⁵³ + 1 は表せず 2⁵³ に丸められるので、2^53+1-2^53 は 1 ではなく 0 になります。足した 1 が、和を保存した時点で消えてしまったのです。
SciKey が 2進・8進・16進を絶対値 2⁵³ 以下の整数にだけ表示するのはこのためで、それを超えると下位の桁は保証されません。16 桁を超えるカード番号や ID を数値として扱うと末尾の桁が変わってしまうのも同じ理由です。
7. 桁落ち: 最も危険な誤差
ほぼ等しい二つの数を引き算すると、上位の桁が打ち消し合い、ほとんど誤差だけが残ります。これを桁落ちといいます。
例 1. (1+1E-15)-1 は本来 10⁻¹⁵ ですが、倍精度では 1.11022302463×10⁻¹⁵ になります。1 + 10⁻¹⁵ を保存するときに 10⁻¹⁶ 程度の丸め誤差が入り、1 を引いたあとではその誤差が結果の 11% を占めます。
例 2. x = 10⁸ のとき √(x²+1) − x は約 5×10⁻⁹ です。そのまま計算すると √(10¹⁶+1) は 10⁸ と区別できず、結果は 0 になります。有理化すれば、引き算のない同値な式が得られます。
√(x²+1) − x = 1 / (√(x²+1) + x)
x に 10⁸ を保存して 1/(sqrt(x^2+1)+x) を計算すると、5×10⁻⁹ が正確に得られます。
例 3. 1 − cos(10⁻⁸) は約 5×10⁻¹⁷ ですが、cos(10⁻⁸) はちょうど 1 に丸められ、そのまま計算すると 0 になります。恒等式 1 − cos x = 2 sin²(x/2) を使えば、2sin(0.5E-8)^2 で 5×10⁻¹⁷ が得られます(RAD モード)。
表示桁数をいくら増やしてもこれは直りません。式を書き換える必要があります。
8. 実践のコツ
- 厳密な等号で比べない。 計算した二つの結果を比べるときは、差が十分小さいか(たとえば相対誤差 10⁻¹²)を確認します。
- お金は整数単位で扱う。 最小の通貨単位の整数で計算すれば、小数の誤差が積み重なりません。
- ほぼ等しい数の引き算を避ける。 有理化、恒等式、式の変形で引き算をなくします。
- 大きな数は比で扱う。 階乗やべき乗が大きくなりすぎるときは、nCr や対数を使うか、先に約分します。
- 途中の結果を丸めない。 倍精度の誤差は 10⁻¹⁶ 程度ですが、手で 4 桁に丸めると 10⁻⁴ 程度の誤差が入ります。大きな誤差はたいてい機械ではなく人から生まれます。
- 表示を 15 桁にしてみる。 結果がおかしく見えたら、桁数を増やして内部の値を確かめ、末尾の桁の誤差なのか、式そのものが間違っているのかを見分けましょう。