我目前正在上一门课程,其中讲师使用以下代码在Java中实现平方根功能-

public class Sqrt {
    public static void main(String[] args) {

        // read in the command-line argument
        double c = Double.parseDouble(args[0]);
        double epsilon = 1.0e-15;  // relative error tolerance
        double t = c;              // estimate of the square root of c

        // repeatedly apply Newton update step until desired precision is achieved
        while (Math.abs(t - c/t) > epsilon*t) {
            t = (c/t + t) / 2.0;
        }

        // print out the estimate of the square root of c
        System.out.println(t);
    }

}


但是,如果我将while循环条件稍微更改为while (Math.abs(t - (c / t)) >= epsilon)而不是while (Math.abs(t - (c / t)) >= t * epsilon),则对于某些输入(如234.0),程序将陷入无限循环。

我使用了Eclipse调试器,发现我的代码在某个点之后返回的值t接近234的平方根,但仍然大于EPSILON。并使用更新公式,在每次迭代后产生相同的t值,因此循环永远停留在那里。

有人可以解释为什么使用>= EPSILON时程序失败,但是使用>= t * EPSILON时效果很好吗?根据我的理解,由于EPSILON的值非常小,因此t * EPSILON最终应该与EPSILON并没有太大的区别,但是在程序中实现时,差异却很大。

最佳答案

double的精度约为15位(或1到2 ^ 52或4.5e15)。计算t * epsilon时,您要求的误差为1到1e15/234的比率,而这可能是double;当您使用epsilon时,您要求的比率是1到1e15的比率是在精度为double的精度,除非它是一个精确值且误差为0。例如对256尝试此操作,它可能会起作用,但是任何不完全相同的值都可能无效。

对于任意端点的一种简单解决方案是,一旦错误从一次迭代到下一次迭代没有改善,就停止。这将使用该公式为您提供最准确的解决方案。

10-07 19:18
查看更多