我试图取一个19位数字的平方根(1121314151617181910.0)并注意到“开箱即用”Operators.sqrt
似乎失败了。我自己编写算法很好但是想知道是否有一个不同的平方根用于大浮动,我不知道并且可以利用。
let testSqrt (square:float)=
let root = sqrt square
(root * root) = square
testSqrt 1090000006.0 // true
testSqrt 1090000007.0 // false
答案 0 :(得分:3)
不只是大值会导致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
在正确答案的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
范围内:
float
然而,即使不能使用非常大的数字,因为let root = sqrt 1121314151617181910.0
1121314151617181910.0 - root * root // 128.0, WAY larger than epsilon
类型只有64位的精度可以使用,并且按照这个速度,你会失去很多舍入错误:
decimal
F#中的sqrt
类型将会达到任意精度,您可以使用,但您必须自己实施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'
实施:
decimal
注意:如果您使用let d = decimal 1121314151617181910.0 // 1121314151617180000M; float lost some precision
let d' = 1121314151617181910M // Correct value, 1121314151617181910M
函数将float转换为十进制,如果数字太大而无法完全适合浮点数,您仍可能会出现舍入错误:
_downloads
答案 1 :(得分:3)
浮点数学并不准确。像0.2这样的简单值无法使用二进制浮点数精确表示,浮点数的有限精度意味着操作顺序的微小变化可能会改变结果。不同的编译器和CPU架构以不同的精度存储临时结果,因此结果将根据您的环境的详细信息而有所不同。如果您进行计算,然后将结果与某个预期值进行比较,那么您很可能无法获得预期的结果。 这就是为什么比较浮动的正确方法是这样的:
{{1}}