Math sqrt(x+;a)-sqrt(x)的数值稳定性评价

Math sqrt(x+;a)-sqrt(x)的数值稳定性评价,math,floating-point,numeric,Math,Floating Point,Numeric,对于全参数范围x,a>=0,是否有一种在数值上稳定计算以下表达式的优雅方法 f(x,a) = sqrt(x+a) - sqrt(x) 还有没有提供这种功能的编程语言或库?如果是,用什么名字?我现在使用上面的表达式没有具体问题,但在过去遇到过很多次,总是认为这个问题以前一定已经解决了 是的,有!如果x和a中至少有一个为正,则可以使用: f(x, a) = a / (sqrt(x + a) + sqrt(x)) 它在数值上是完全稳定的,但其本身几乎不值得一个库函数。当然,当x=a=0时,结果应该

对于全参数范围x,a>=0,是否有一种在数值上稳定计算以下表达式的优雅方法

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

还有没有提供这种功能的编程语言或库?如果是,用什么名字?我现在使用上面的表达式没有具体问题,但在过去遇到过很多次,总是认为这个问题以前一定已经解决了

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

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+a
x
的值非常接近(或者相当于
a
的大小比
x
小得多)。例如,如果
x=1
a
很小,我们从
1
周围的泰勒展开式知道
sqrt(1+a)
应该是
1+a/2-a^2/8+O(a^3)
,因此
sqrt(1+a)-sqrt(1)
应该接近
a/2-a^2/8
。让我们为小
a
的特定选择尝试一下。以下是原始函数(在本例中是用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
,在IEEE 754双精度浮点的上下文中,立方和更高阶项是无关紧要的,它只提供大约16位小数精度。让我们计算该值以进行比较:

>>> a/2 - a**2/8
9.999999999500001e-11

这正是我想要的。虽然它对x=a=0不起作用,但它比原来的好得多。啊,好的一点。是的,对于库质量函数,您需要使用特例
x=a=0
。我在特例中编辑了
a=0
。谢谢你的更正!谢谢您是否碰巧知道某个资源,其中列出了某些函数的数值稳定评估?像是一本手册吗?我发现在互联网上搜索特定的公式特别困难…@DonHatch我想是的。即使
x
和/或
a
是次正常值,并且继续假设
x
a
都是非负的,平方根也在正常范围内,因此我看不到任何地方会损失超过几个ULP的精度。(用一点时间和一张足够大的纸,应该可以得出ulps中错误的实际上限。)嗯,尽管现在我注意到我并不坚持
x
a
都是非负的。需要一些思考。一些库,尤其是Boost,提供了一个函数
sqrt1pm1()
,用于精确计算sqrt(x+1)-1。如果您已经使用了这样一个库,您可以使用该函数以数字健壮的方式将
sqrt(x+a)-sqrt(x)
实现为
sqrt1pm1(a/x)*sqrt(x)
。@njuffa:啊,非常有趣。虽然像
log1p
expm1
这样的函数很常见,但我以前从未遇到过
sqrt1pm1
。一方面,当它很容易仿真时,为它创建一个单独的函数似乎很奇怪。另一方面,如果它在C标准库中可用,我肯定会有机会使用它。@MarkDickinson正如Kahan所示,
log1p
expm1
也很容易模拟。在库中提供此类函数的目的大概是为那些对数值分析不太了解的程序员提供最快、最准确的实现。@njuffa:我想说,这是“easy”的一个完全不同的值例如,请参阅示例,了解在浮点格式和当前舍入模式都不能依赖的情况下,尝试模拟
log1p
所涉及的注意事项。@njuffa:了解sqrtpm1函数很有意思。这其实是我想学的。。。这种方法的缺点当然是必须加上x=0的特例。。。
>>> a/2 - a**2/8
9.999999999500001e-11