我目前正在上一门课程,其中讲师使用以下代码在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
尝试此操作,它可能会起作用,但是任何不完全相同的值都可能无效。
对于任意端点的一种简单解决方案是,一旦错误从一次迭代到下一次迭代没有改善,就停止。这将使用该公式为您提供最准确的解决方案。