【问题标题】:Numerically stable evaluation of sqrt(x+a) - sqrt(x)sqrt(x+a) - sqrt(x) 的数值稳定评估
【发布时间】:2015-09-07 19:13:57
【问题描述】:

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

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

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

【问题讨论】:

  • 一些库,尤其是 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:我想说这是“简单”的一个完全不同的价值。 :-) 例如,请参阅Python source,了解在不能依赖浮点格式和当前舍入模式的情况下尝试模拟 log1p 所涉及的注意事项。
  • @njuffa:了解 sqrtpm1 函数很有趣。这其实是我想学的...这种方法的缺点当然是必须添加 x=0 的特殊情况...

标签: math floating-point numeric


【解决方案1】:

是的,有!如果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 f(x, a):
    return sqrt(x + a) - sqrt(x)

这是稳定版:

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 都是非负数,平方根也在正常范围内,所以我看不到任何地方您将损失的不仅仅是少数几个 ulps 的准确性。 (用一点时间和一张足够大的纸,应该可以得出 ulps 误差的实际上限。)嗯,虽然现在我注意到我并不坚持 x和a 是非负数。需要考虑一下。
猜你喜欢
  • 2018-12-16
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
相关资源
最近更新 更多