sqrt(x + a) - sqrt(x)的数值稳定评估

时间:2015-09-07 19:13:58

标签: math floating-point numeric

是否有一种优雅的数值稳定方式来评估完整参数范围x的以下表达式,a> = 0?

f(x,a) = sqrt(x+a) - sqrt(x)

还有任何编程语言或库提供这种功能吗?如果是,以什么名义?我现在使用上面的表达式没有具体问题,但过去曾多次遇到过这种情况,并且始终认为这个问题必须先解决!

1 个答案:

答案 0 :(得分:12)

是的,有!如果xa中至少有一个为正数,则可以使用:

f(x, a) = a / (sqrt(x + a) + sqrt(x))

这是完全数值稳定的,但它本身几乎不值得图书馆功能。当然,在x = a = 0时,结果应为0

说明:sqrt(x + a) - sqrt(x)等于(sqrt(x + a) - sqrt(x)) * (sqrt(x + a) + sqrt(x)) / (sqrt(x + a) + sqrt(x))。现在将前两个项相乘得到sqrt(x+a)^2 - sqrt(x)^2,这简化为a

以下是一个展示稳定性的示例:原始表达式的麻烦案例是x + ax的值非常接近(或者当a的数量远小于xx = 1)。例如,如果a1很小,我们知道围绕sqrt(1 + a)的泰勒展开1 + a/2 - a^2/8 + O(a^3)应该是sqrt(1 + a) - sqrt(1),那么a/2 - a^2/8应该接近a。让我们尝试一下特定的小def f(x, a): return sqrt(x + a) - sqrt(x) 选择。这是原始函数(在本例中用Python编写,但您可以将其视为伪代码):

def g(x, a):
    if a == 0:
        return 0.0
    else:
        return a / ((sqrt(x + a) + sqrt(x))

这是稳定的版本:

x = 1

现在让我们看一下a = 2e-10>>> a = 2e-10 >>> f(1, a) 1.000000082740371e-10 >>> g(1, a) 9.999999999500001e-11

的结果
a/2 - a^2/8

我们应该得到的值是(达到机器精度):a - 对于这个特定的>>> a/2 - a**2/8 9.999999999500001e-11 ,在IEEE 754双精度浮点数的上下文中,立方和高阶项是无关紧要的,它只提供大约16位十进制数字的精度。让我们计算一下这个值进行比较:

lvl=100 (2626 KB for nbparts) 9522 possible passwords
lvl=101 (2652 KB for nbparts) 10 K possible passwords (10604)
lvl=102 (2678 KB for nbparts) 11 K possible passwords (11805)
...
lvl=213 (5564 KB for nbparts) 956 M possible passwords (956026029)
lvl=214 (5590 KB for nbparts) 1 G possible passwords (1058500959)
lvl=215 (5616 KB for nbparts) 1 G possible passwords (1171975083)
...
lvl=400 (10426 KB for nbparts) 29926014 G possible passwords (29926014173292546)