GHCIが1.1 + 1.1 + 1.1> 3.3が真実だと言うのはなぜですか?
-
19-09-2019 - |
質問
私は最近Haskellチュートリアルを見てきましたが、インタラクティブでいくつかの簡単なHaskell式を試してみると、この動作に気付きました ghci
シェル:
Prelude> 1.1 + 1.1 == 2.2
True
Prelude> 1.1 + 1.1 + 1.1 == 3.3
False
Prelude> 1.1 + 1.1 + 1.1 > 3.3
True
Prelude> 1.1 + 1.1 + 1.1
3.3000000000000003
なぜそれがなぜなのか知っていますか?
解決
なぜなら 1.1
と 3.3
それは 浮動小数点数. 。 .1や.3などの小数の画分は、バイナリの浮動小数点数で正確に表現できません。 .1は1/10を意味します。それをバイナリで表すには、各分数桁が1/2を表しますn (1/2、1/4、1/8など)、無限の数字、0.000110011が必要になります...無限に繰り返されます。
これは、たとえば、ベース10の1/3を表すのとまったく同じ問題です。ベース10では、1/3を正確に表すために、永遠に無限の数字の数字、.33333が必要です。したがって、ベース10で作業して、通常は.33のようなものになります。ただし、その3つのコピーを合計すると、1ではなく.99を取得します。
トピックの詳細については、お読みください すべてのコンピューター科学者が浮動点の算術について知っておくべきこと.
Haskellでより正確に合理的な数値を表すために、いつでも合理的なデータ型を使用できます。 Ratio
;ビグノムと相まって(任意に大きな整数、 Integer
とは対照的に、Haskellで Int
分子と分母のタイプとして、任意の正確な合理的な数値を表すことができますが、ハードウェアで実装され、速度で最適化されている浮動小数点数よりもかなり遅い速度で表現できます。
浮動小数点数は、科学的および数値計算、高速で精度をトレードオフする最適化であり、丸めとそれが計算にどのように影響するかを知っている限り、非常に多数の計算を少量で実行できるようになります。 。
他のヒント
浮動小数点数は正確ではないためです(ウィキペディア)
合理的なタイプを使用して、Haskellの浮動小数点エラーを回避できます。
Prelude Data.Ratio> let a = (11 % 10) + (11 % 10) + (11 % 10)
Prelude Data.Ratio> a > (33 % 10)
False
Prelude Data.Ratio> fromRational a
3.3
もちろん、精度の向上に対してパフォーマンスペナルティを支払います。
典型的なフローティングポイントエラーの問題のように見えます。
IEEEの浮動小数点数の動作方法に関係しています。
1.1は、フローティングポイントで1.1000000000000001として表され、3.3は3.29999999999999として表されます。
したがって、1.1 + 1.1 + 1.1は実際にです
1.1000000000000001 + 1.1000000000000001 + 1.1000000000000001 = 3.3000000000000003
ご覧のとおり、実際には3.29999999999998よりも大きいです。
通常の回避策は、平等を評価しないか、数値がターゲット+/-小さなイプシロン内にあるかどうかを確認することです(必要な精度を定義します)。
例:両方が真である場合、合計は3.3に「等」です(許可エラー内)。
1.1 + 1.1 + 1.1 < 3.3 + 1e9
1.1 + 1.1 + 1.1 > 3.3 - 1e9
IEEE 754表現を使用して正確に表現できるフロートはほとんどないため、常に少し離れています。
一般に、フロートを平等について比較するべきではありません(上記の理由のため)。私が考えることができる唯一の理由は、「この価値が変わった」と言いたい場合です。たとえば、「if(newscore /= oldscore)」の場合、何らかのアクションを実行します。 2つの個別の計算の結果を比較して、それらがたまたま等しいかどうかを確認していない限り、それは大丈夫です(その後、もしそうであれば、それ以外の場合は数学的に丸められる可能性があるため)。