4

大きな整数を定義することから始めますn

Prelude> let n = 5705979550618670446308578858542675373983
Prelude> n :: Integer
5705979550618670446308578858542675373983

次に、 と の動作を調べましs1s2

Prelude> let s1 = (sqrt (fromIntegral n))^2
Prelude> let s2 = (floor(sqrt(fromIntegral n)))^2

Prelude> s1 == fromIntegral n
True
Prelude> s1 == fromIntegral s2
True
Prelude> (fromIntegral n) == (fromIntegral s2)
False

小数部分は破棄される可能性があるため、最後の 2 つの式が等しいとは予想されませんでした。しかし、平等が自動詞であるとは思っていませんでした (例: n == s1, s1 == s2, but n != s2.)。

さらに、floor40 桁の有効数字を保持しているにもかかわらず、整数部分の精度が失われているようです。

Prelude> s1
5.70597955061867e39

Prelude> s2
5705979550618669899723442048678773129216

この失われた精度は、減​​算をテストすると明らかになります。

Prelude> (fromIntegral n) - s1
0.0

Prelude> (fromIntegral n) - (fromIntegral s2)
546585136809863902244767

精度が失われるのはなぜですか?floorまた、これがどのように等号の推移性に違反していますか?

floor . sqrt精度を落とさずに計算するための最良のアプローチは何ですか?

4

1 に答える 1

15

floor精度が失われているわけではありませんが、 Integer(任意精度の整数) からDouble(精度が制限されている浮動小数点値) への変換です。したがって、fromIntegral n :: Doubleは と同じ値ではなくなりますn

Double53 ビットの仮数部 (52 が明示的に格納され、先頭の 1 つは暗示的) を持ち、これは 10 進数の 16 桁にほぼ相当します。したがって、結果の最上位 (約) 16 桁のみが有効です。残りは単なるノイズです。

最後に、最初の 2 つの比較でDoubles を比較します。とn に変換さDouble、 にs2 変換さDouble、 とs1はすべて等しいです。ただし、3 番目の比較では、ns2は両方ともIntegers です。それらは s として比較できるIntegerため、それらの呼び出しfromIntegralはノーオペレーションであり、変換されていない整数値は異なります。への変換を強制するDoubleと、値は再び等しくなります。

Prelude> ((fromIntegral n) :: Double) == ((fromIntegral s2) :: Double)
True
于 2013-08-14T20:13:26.330 に答える