TERM PRIMER
0.1+0.2の誤差|先に知っておく言葉
0.1や0.2は、二進数の限られた桁ではぴったり保存できず、少し違う近い値になります。その値で計算するため、結果も数学上の0.3とずれることがあります。表示の桁を減らしても、保存済みの値は変わりません。
紙の上なら、0.1+0.2は0.3です。ところがPythonで同じ式を試すと、末尾に小さな数字が付くことがあります。
>>> 0.1 + 0.2
0.30000000000000004
足し算の決まりが変わったのでしょうか。手がかりは、足す前の 0.1 が、コンピューターの中でどんな値になっているかです。この記事の実行例は、CPython 3.14.6/arm64、2進・53ビット精度の float で確認しています。
二進数では、0.1を書き終えられない
日常使う十進数でも、1÷3を小数で書くと 0.333… と続きます。二進数にも、有限の桁では書き終えられない小数があります。その一つが、十進数の0.1です。
二進数の小数部分は、左から 1/2、1/4、1/8、1/16……の位になります。0.5なら 1/2 一つなので、二進数では 0.1。一方、十進数の0.1は、二進数では 0.0001100110011… と続きます。 同じ「0.1」という見た目でも、十進数と二進数では値が違う点に注意してください。
保存に使える桁数には限りがあります。書き終わらない小数をそのまま全部保存できないので、表せる値のうち近いものを選びます。粗い目盛りで、その様子を見てみます。
- A
- 0.0625
- B
- 0.1
- C
- 0.125
この模型では0.1を0.125に丸めましたが、実際の float がここまで大きくずれるわけではありません。Pythonの今回の環境では、0.1は次の値として保存されました。長い数字を覚える必要はなく、0.1より少し大きいところだけ見てください。
0.1000000000000000055511151231257827021181583404541015625
有効な数字の部分と、小数点の位置を動かす情報を組み合わせて数を表す方式を「浮動小数点」といいます。ここで扱うのは二進数を使う方式です。大きな数も小さな数も扱えますが、あらゆる小数をぴったり表せるわけではありません。模型の目盛りは等間隔ですが、実際の浮動小数点で隣り合う値の間隔は、値の大きさによって変わります。
保存した値が違っても、画面には0.1と出せる
ここで、少し不思議なことが起こります。Pythonで 0.1 をそのまま表示すると、長い数字ではなく、いつもの 0.1 が出ます。
>>> 0.1
0.1
通常の表示では、保存した値を十進数で最後まで書き出すとは限りません。短く表示しても、読み戻したときに同じ float の値になる表し方が選ばれます。つまり、画面の「0.1」は、保存した値の全桁を見せたものではないのです。
「保存するために近い値を選ぶこと」と「画面に出す桁を絞ること」は別の処理です。足し算で末尾が見えてくる理由も、この二つを分けると追いやすくなります。
0.1+0.2と0.3を、保存した値で比べる
0.1 だけでなく、0.2 も近い値として保存されます。その二つを足し、結果を保存できる値に丸めると、今回の環境では 0.30000000000000004 と表示される値になりました。
では、最初から 0.3 と入力した値はどうでしょう。これもぴったりの3/10ではなく、少し小さい値になります。二つはとても近いのですが、同じではありません。
>>> x = 0.1 + 0.2
>>> y = 0.3
>>> x == y
False
== は「保存した二つの値が等しいか」を調べます。False は「等しくない」という結果です。人が小数点以下1桁だけを見れば同じ0.3に見えても、この比較では違いが残ります。
表示をそろえたら、同じ値になる?
二つの値を保存してから、表示のしかただけを変えます。
保存した計算・入力
0.1 + 0.2通常の表示
0.30000000000000004保存した計算・入力
0.3通常の表示
0.3両方を小数点以下1桁で表示する
format(x, '.1f')0.3format(y, '.1f')0.3見た目はどちらも 0.3。でも、保存済みの x と y は書き換わっていません。
x == y の結果は False(同じ値ではない)のままです。
保存した値を、十進数で省略せずに見る
- x の値
0.3000000000000000444089209850062616169452667236328125- y の値
0.299999999999999988897769753748434595763683319091796875
数字は折り返して表示しています。途中を省略していません。
CPython 3.14.6 / arm64、2進・53ビット精度の float で確認した結果です。ブラウザ内でPythonを実行する教材ではありません。
短い表示に変えると、見た目の末尾は消えます。でも、表示だけを変えても、元の値の違いは消えません。 どこまで近ければ同じとみなすかは、計算の目的に合わせて別に決めることです。小数点以下を隠せば、どんな比較も解決するというわけではありません。
すべての小数で、同じずれが出るわけではない
二進数で有限の桁に収まる小数もあります。0.5は1/2、0.25は1/4なので、今回の float では正確に表せます。足した0.75も3/4として正確です。
>>> 0.5 + 0.25
0.75
「コンピューターは小数を間違える」とまとめるより、「使う数の表し方によって、ぴったり保存できる数と、近い値になる数がある」と考えると、二つの例を一緒に説明できます。
計算結果を使うときは、何をそろえたいかで選ぶ
末尾の数字を見つけたら、まず表示だけを整えたいのか、値を比較したいのかを分けます。
| したいこと | Pythonで調べる手段 | 気をつけること |
|---|---|---|
| 小数点以下1桁で見せる | format(x, '.1f') | 表示用の文字列になる。元の値は変わらない |
| 二つの値が十分近いか比べる | math.isclose(x, y) | 許容する差は、計算の目的に合わせて決める |
| 十進数や分数として計算する | decimal、fractions | 数を入力する段階から、その方式を使う |
詳しい使い方は、Python公式の浮動小数点の説明から各機能へ進めます。丸め方を一つ覚えてすべてに当てはめるより、何のための数かを先に考えることが大切です。
誰かに理由を聞かれたら、こんなふうに言えます。「0.1は二進数では終わらないから、近い値を保存するんだ。その値で計算して、最後に見やすい桁数で表示しているんだよ」。
では、使える0と1の桁を増やすと、表せる組み合わせはどう増えるのでしょう。ビットの組み合わせを試す記事では、スイッチを増やしながら確かめられます。
LAB WHITEBOARD
0.1+0.2の誤差を一文で説明してみよう
「小数を近い値で保存することと、表示する桁を減らすことを分けて説明できる。」を、いまの自分の言葉で一文にしてみてください。途中の説明でも大丈夫です。




