[ 最終更新日: 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