蔵風人

If you try it, it will be somehow & Simple is Best!


[ 最終更新日: 2026-06-20 01:56 閲覧回数: 18回 ]

浮動小数点数の計算時の注意

電卓と異なる結果

浮動小数点数の計算では、通常使っている電卓と異なる結果が出ます。一例をあげると以下のとおり。

>>> data1 = 0.2
>>> data2 = 3
>>> print(data1 * data2)

結果は 0.6 ではなく、0.6000000000000001 です。したがって、

>>> data1 * data2 == 0.6
False
>>> 

となります。

なぜか?参考書によると「pythonは内部的に2進数で演算じているため(0.2は2進数で0.00110011... の無限循環少数)」と書いてありました。ふ〜ん。

ではどうすればよいのか?

Decimal 型を使用する

>>> import decimal
>>> data1 = decimal.Decimal('0.2') # 浮動小数点数だけ Decimal 型に変更する
>>> data1 * data2 == 0.6
False # 0.6 等しくはならないと行っています。
>>> data2 = decimal.Decimal('3') # data2 は不動小数点ではなく int 型なのですが、整数部もDecimal 型に変更します
>>> data1 * data2 == 0.6
False  # これでも 0,6 とは等しくないと行っています。 
>>> print(data1 * data2)
0.6 # でも、計算結果は一見すると等しいように見えます。
>>> data1 * data2 == decimal.Decimal('0.6') # 答えの部の浮動小数点数も Decimal 型に変換
True # これでやっと電卓と同じ結果になります。

結論はすべての変数を Decimal 型に変換して計算すべき。

どうも腑に落ちない〜実際にはどのような数値が代入されているのか?

以上の結果で、整数すら型変換しないとだめ、ということになりますが、そもそも変数にはどのような数字が入っていたのか、を調べてみました。

>>> del data1
>>> del data2
>>> data1 = 0.2
>>> print(data1)
0.2 # 間違いなく0.2 という数字です。

でも表示桁数を増やしていくとどうなるでしょうか?

>>> print(f'{data1:.16f}')
0.2000000000000000
>>> print(f'{data1:.17f}')
0.20000000000000001
>>> print(f'{data1:.30f}')
0.200000000000000011102230246252

以上のとおり、小数点以下16桁までは 0.2 で、17桁から1が増えています。だから data1 = 0.2 とやっても、実際には 0.20000000000000001....が代入されていることになります。

そうであれば、小数点以下16桁までの数字で計算すれば、Decimal 型に変換しなくてもできるのではないか?と思いましたが、

異なる数値だと16桁の前(すなわち15桁)で数値が変更になることがありますので、素直に Decimal 型を使うべきのようです。

>>> data1 = 0.5 # 小数点以下1桁だと16桁までおなじ
>>> print(f'{data1:.16f}')
0.5000000000000000
>>> data1 = 0.56 # 小数点以下2桁だと15桁で数字が異なってくる
>>> print(f'{data1:.16f}')
0.5600000000000001
>>> data1 = 0.568
>>> print(f'{data1:.16f}')
0.5679999999999999