Pythonで浮動小数点数を丸めることを検討していますが、次の動作は非常に奇妙に思えます。
コード:
a = 203.25
print '%.2f'%(a/10.)
print '%.2f'%(round(a/10., 2))
print '%.2f'%(0.1*a)
出力:
20.32
20.32
20.33
最初のケース、特に2番目のケースが失敗するのはなぜですか?
Pythonで浮動小数点数を丸めることを検討していますが、次の動作は非常に奇妙に思えます。
コード:
a = 203.25
print '%.2f'%(a/10.)
print '%.2f'%(round(a/10., 2))
print '%.2f'%(0.1*a)
出力:
20.32
20.32
20.33
最初のケース、特に2番目のケースが失敗するのはなぜですか?
http://en.wikipedia.org/wiki/Rounding#Round_half_to_even
半分を偶数に丸める
偏りの少ないタイブレーク ルールは、半分を偶数に丸めます。つまり、次のようになります。y の分数が 0.5 の場合、q は y に最も近い偶数の整数です。したがって、たとえば、+23.5 は +24 になり、+24.5 も同様です。一方、-23.5 は -24.5 と同様に -24 になります。
この方法では、正と負の値が対称的に扱われるため、符号の偏りがありません。さらに重要なことは、y 値の妥当な分布では、丸められた数値の期待 (平均) 値が元の数値と同じになることです。ただし、このルールでは、偶数の場合はゼロに向かうバイアスが導入され、奇数の場合は無限に向かうバイアスが導入されます。
この近辺への丸め法の変形は、不偏丸め、収束丸め、統計的丸め、オランダ丸め、ガウス丸め、奇偶丸め、または銀行員丸めとも呼ばれ、簿記で広く使用されています。
これは、IEEE 754 計算関数および演算子で使用されるデフォルトの丸めモードです。
>>> "%.2f"%20.325
'20.32'
>>> "%.2f"%20.335
'20.34'
>>> "%.2f"%20.345
'20.34'
>>> "%.2f"%20.355
'20.36'
では、本当の問題は、なぜ 3 番目のケースが失敗するのかということです。
203.25
浮動小数点表現で正確に表現できますが、表現0.1
できません。0.1
>>> 0.1*203.25
20.325000000000003
だから丸くなる
これはおそらく答えの一部です:
>>> a*.1
20.325000000000003
>>> a/10
20.325
IEEE 754 丸めの実装方法については、@gnibblers の説明を参照してください。
これらのケースが期待どおりに機能しない理由についての具体的な詳細はわかりませんが、浮動小数点数で厳密な精度が必要な場合は、 decimal モジュールのようなものを使用してください。
printf を使用して、何が起こっているかを確認できます
print '%0.20f'%20.325
20.32499999999999928946
Python docs for round()
point to the answer. 基本的に、浮動小数点は一部の数値を正確に表すことができません。たとえば、0.1
は のようになり0.10000000000000001
ます。この不正確さにより、予期しない結果が生じることがあります。浮動小数点数を使用して、特定の許容範囲内で計算を行うことは非常に困難です。あなたのケースで計算が機能する理由は0.1 * a
、丸めの目的の方向にわずかに偏っているためです。
本当に精度が必要な場合は、Decimal モジュールの使用を検討する必要があります。10 進数での作業も雑用になる可能性がありますが、必要な精度を得るのが少し簡単になります。
失敗はありません。すべてのプログラマーが浮動小数点演算について知っておくべきことを参照してください。