如何将浮动的sqrt高于1090000006.0?

时间:2016-11-01 05:36:08

标签: f#

我试图取一个19位数字的平方根(1121314151617181910.0)并注意到“开箱即用”Operators.sqrt似乎失败了。我自己编写算法很好但是想知道是否有一个不同的平方根用于大浮动,我不知道并且可以利用。

let testSqrt (square:float)= 
    let root = sqrt square
    (root * root) = square

testSqrt 1090000006.0 // true
testSqrt 1090000007.0 // false

2 个答案:

答案 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}}