testSqrt
の機能に失敗するだけでなく、大きな値でもありません。見る:
let testSqrt (square:float)=
let root = sqrt square
(root * root) = square
testSqrt 2.0 // false!
ここで起こっていることはrounding errorです。 sqrt
が2の平方根を計算すると、不合理な数が得られますが、その数を有限数のビットに格納する必要があります。したがって、ある点で四捨五入して1.414213562
を生成します。そして、あなたはそれ自体で1.414213562
を掛けたとき、あなたはに非常に近いです数が、に正確に等しいではない、2入手:
let root = sqrt 2.0
abs (2.0 - root * root) // 4.440892099e-16
が正しくsqrt
をテストするために、それはより大きくなりますいくつかの小さな値epsilon
を定義する方が良いでしょうあなたの丸め誤差期待、およびroot * root
値が正しい答えのepsilon
内にあるであろうことを確認してください:float
タイプのみの精度の64ビットを持っているのでしかし、それは、非常に大きな数字では動作しません
let epsilon = 1.0e-6
let testSqrt (square:float)=
let root = sqrt square
abs (square - root * root) < epsilon
testSqrt 1090000006.0 // true
testSqrt 1090000007.0 // now this is also true
一緒に働くあなたはsqrt
を自分で実装する必要がありますけれども、あなたが、使用できる任意の精度に行くF#でdecimal
タイプがあります
let root = sqrt 1121314151617181910.0
1121314151617181910.0 - root * root // 128.0, WAY larger than epsilon
:、及びその割合で、あなたは丸め誤差からLOTを失っていますそれはdecimal
のために実装されていないので、:
let d = decimal 4 // Prints as 4M
let d' = 4M // Another way to write "decimal 4"
sqrt d // Error FS0001: The type 'decimal' does not support the operator 'Sqrt'
は注意してください:あなたは10進数浮動小数点数を変換するdecimal
機能を使用している場合、数がfloatで完全にフィットする大きすぎた場合、あなたはまだエラーを丸めることがあります。
let d = decimal 1121314151617181910.0 // 1121314151617180000M; float lost some precision
let d' = 1121314151617181910M // Correct value, 1121314151617181910M
丸め誤差について知っていますか?そのため、 '(root * root)= square'があなたのために働いていないのです。 'testSqrt 2.0'も** ** falseであることに注意してください!これは、 'let root = sqrt 2.0; (ルート*ルート) - 2.0は丸め誤差のために '4.440892099e-16'です。あなたが必要とするのは、 'abs(square-root * root)'が非常に小さな数、例えば '1.0e-6'未満であることをテストすることです。 – rmunn
不快な投稿です。はい、丸め誤差を認識しています。あなたは19桁の数字の平方根がないと言っていますか? – jks612
'double'は53ビットの仮数を「ちょうど」持っています。これは約16小数です。 'BigInteger'を使って任意の精度で大きな有理型を実装し、Newton-Raphsonを使って' sqrt'を実装することができます。しかし、あなたが知っているように、多くの平方根は、不合理な数として定義されます。定義上、有理数で表すことはできません。また、表現ツリーとして結果を表現することも可能です。これは、あなたが得ることができる正確な表現木です。 – FuleSnabel