【问题标题】:How to Correctly Round a Square Root Function?如何正确舍入平方根函数?
【发布时间】:2019-02-14 13:01:27
【问题描述】:

我目前正在开发一个 Java 数学库,其中将包含各种正确舍入的函数(即 sqrt、cbrt、exp、sin、gamma 和 ln)。我已经使用巴比伦方法编写了一个平方根算法,该算法在正确答案的 1 ulp 范围内是正确的。但是,我无法弄清楚如何正确计算数字应该以哪种方式四舍五入以表示对输入实际平方根的最佳近似值。包含可以扩展到其他函数的原理的答案将是首选,但我听说 sqrt 比许多超越函数更简单,并且也非常感谢专门的解决方案。

此外,这是我的代码在此问题原始提交时的清理版本:

public static double sqrt(double x) {
    long bits = Double.doubleToLongBits(x);

    // NaN and non-zero negatives:
    if (Double.isNaN(x) || x < 0) return Double.NaN;

    // +-0 and 1:
    if (x == 0d || x == 1d) return x;

    // Halving the exponent to come up with a good initial guess:
    long exp = bits << 1;
    exp = (exp - 0x7fe0000000000000L >> 1) + 0x7fe0000000000000L >>> 1 & 0x7ff0000000000000L;
    double guess = Double.longBitsToDouble(bits & 0x800fffffffffffffL | exp);
    double nextUp, nextDown, guessSq, nextUpSq, nextDownSq;

    // Main loop:
    while (true) {
        guessSq = guess * guess;
        if (guessSq == x) return guess;
        nextUp = Math.nextUp(guess);
        nextUpSq = nextUp * nextUp;
        if (nextUpSq == x) return nextUp;
        if (guessSq < x && x < nextUpSq) {
            double z = x / nextUp;
            if (z * nextUp > x) z = Math.nextDown(z);
            return z < nextUp ? nextUp : guess;
        }
        nextDown = Math.nextDown(guess);
        nextDownSq = nextDown * nextDown;
        if (nextDownSq == x) return nextDown;
        if (nextDownSq < x && x < guessSq) {
            double z = x / guess;
            if (z * guess > x) z = Math.nextDown(z);
            return z < guess ? guess : nextDown;
        }

        // Babylonian method:
        guess = 0.5 * (guess + x / guess);
    }
}

如您所见,我使用除法作为测试。但是,我认为这需要将除法四舍五入到 0,这在 Java 中显然不会发生。

【问题讨论】:

  • 这似乎有点宽泛;我建议澄清。你有可以分享的代码吗?您使用什么语言?
  • 请展示您使用巴比伦方法尝试过的内容。如果没有代码,这将是题外话和/或过于宽泛

标签: java math precision floating-accuracy sqrt


【解决方案1】:

根据泰勒定理,平方根函数局部近似为斜率为 1/2√x 的线性函数,为正数。因此,您可以将误差与平方误差 x - (√x)² 联系起来,其中 √x 被理解为近似根。然后你朝最小化这个错误的方向四舍五入。

无论如何,x - (√x)² 的计算会遭受灾难性的抵消,您可能需要更高的精度才能可靠地计算它。不确定这样做的好处是否值得。

【讨论】:

  • 那么逐位计算会更快吗?
  • @EvanBailey:绝对矫枉过正,不要那样做。
猜你喜欢
  • 2013-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-08
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多