問題は、field1 と field2 の合計が 9.5-10.3 のような値で、結果が -0.800000000000001 になることがあります。なぜこれが起こるのか、そしてそれを解決する方法を誰か説明できますか?
なぜこれが起こるのか
float
型と型はdouble
、数値を基数 10 ではなく基数 2 で格納します。数値は、有限のビット数で正確に表現できる場合があります。
9.5 → 1001.1
また、できない場合もあります。
10.3 → 1010.0 1001 1001 1001 1001 1001 1001 1001 1001...
後者の場合、数値は次のように表現できる最も近い値に丸められますdouble
。
1010.0100110011001100110011001100110011001100110011010 base 2
= 10.300000000000000710542735760100185871124267578125 base 10
減算が 2 進数で行われると、次のようになります。
-0.11001100110011001100110011001100110011001100110100000
= -0.800000000000000710542735760100185871124267578125
通常、出力ルーチンはほとんどの「ノイズ」桁を隠します。
- Python 3.1 では丸められます。
-0.8000000000000007
- SQLite 3.6 では に丸められ
-0.800000000000001
ます。
printf %g
に丸め-0.8
ます。
double
値が -0.8 と表示されるシステムでも、-0.8 の最適な近似値とは異なることに注意してください。
- 0.11001100110011001100110011001100110011001100110011010
= -0.8000000000000000444089209850062616169452667236328125
したがって、 を使用するプログラミング言語double
では、式9.5 - 10.3 == -0.8
は false になります。
非decimal
解決策
このような質問に対する最も一般的な答えは、「10 進演算を使用する」です。この特定の例では、実際により良い出力が得られます。Python のdecimal.Decimal
クラスを使用する:
>>> Decimal('9.5') - Decimal('10.3')
Decimal('-0.8')
ただし、まだ対処する必要があります
>>> Decimal(1) / 3 * 3
Decimal('0.9999999999999999999999999999')
>>> Decimal(2).sqrt() ** 2
Decimal('1.999999999999999999999999999')
これらは、2 進数の丸め誤差よりもよく知られている丸め誤差かもしれませんが、重要性が低くなるわけではありません。
実際、次の組み合わせにより、2 進数の分数は同じビット数の 10 進数よりも正確です。
また、専用のハードウェアを備えているため、(PC 上で)はるかに高速です。
ベース 10 について特別なことは何もありません。これは、私たちが持っている指の数に基づいた恣意的な選択です。
生まれたばかりの赤ちゃんの体重が 0x7.5 ポンド (より一般的な用語では、7 ポンド 5 オンス) であると言うのは、体重が 7.3 ポンドであると言うのと同じくらい正確です.許容範囲内です。) 一般に、10 進数は、物理的な測定値を表すのに何の利点もありません。
お金が違う
一定レベルの精度で測定される物理量とは異なり、お金は数えられるため、正確な量になります。奇妙な点は、他のほとんどの離散量のように 1 の倍数ではなく、0.01 の倍数でカウントされることです。
「10.3」が実際に $10.30 を意味する場合は、値を正確に表すために 10 進数タイプを使用する必要があります。
(16 分の 1 ドルだった時代の過去の株価を扱っている場合を除きます。その場合はバイナリで十分です ;-) )
それ以外の場合は、単なる表示の問題です。
有効数字15桁まで正解でした。それはすべての実用的な目的で正しいです。「ノイズ」を隠したいだけの場合は、SQLROUND
関数を使用してください。