2 回答

TA貢獻1780條經驗 獲得超4個贊
您實際上可以使用調試器來查看數字的進展情況以及為什么例如 234 的平方根在epsilon
不乘以時會導致無休止的循環t
。
我已經使用帶有日志斷點的 IntelliJ 來查看數字如何進行以及為什么會發生無休止的循環:
首先,我在日志斷點中使用了這個表達式:
" " + Math.abs(t - c/t) + " " + epsilon
對于此代碼:
private static void calcRoot(String arg) {
// read in the command-line argument
double c = Double.parseDouble(arg);
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 = (c/t + t) / 2.0;
}
// print out the estimate of the square root of c
System.out.println(t);
}
這是證明實際上epsilon小于的結果,Math.abs(t - c/t)并且Math.abs(t - c/t)在其進程中停止:
233.0 1.0E-15
115.50851063829788 1.0E-15
55.82914775415816 1.0E-15
24.47988606961853 1.0E-15
7.647106514310517 1.0E-15
0.927185521197492 1.0E-15
0.014043197832668497 1.0E-15
3.2230278765865705E-6 1.0E-15
1.723066134218243E-13 1.0E-15
1.7763568394002505E-15 1.0E-15
1.7763568394002505E-15 1.0E-15
1.7763568394002505E-15 1.0E-15
1.7763568394002505E-15 1.0E-15
1.7763568394002505E-15 1.0E-15
1.7763568394002505E-15 1.0E-15
1.7763568394002505E-15 1.0E-15
...
如果我然后使用epsilon * tI 并將日志記錄表達式更新為" " + Math.abs(t - c/t) + " " + epsilon * t我可以看到完全不同的控制臺輸出:
233.0 2.34E-13
115.50851063829788 1.175E-13
55.82914775415816 5.974574468085106E-14
24.47988606961853 3.1831170803771985E-14
7.647106514310517 1.959122776896272E-14
0.927185521197492 1.5767674511807463E-14
0.014043197832668497 1.5304081751208715E-14
3.2230278765865705E-6 1.529706015229238E-14
1.723066134218243E-13 1.5297058540778443E-14
更新
如果你在BigDecimal課堂上嘗試同樣的事情,你將能夠計算 的平方根,234以防你選擇足夠的四舍五入數字(見scale下面的變量):
private static void calcRootBig(String arg) {
// read in the command-line argument
BigDecimal c = new BigDecimal(arg);
BigDecimal epsilon = new BigDecimal(1.0e-15); // relative error tolerance
BigDecimal t = new BigDecimal(c.toString()); // estimate of the square root of c
BigDecimal two = new BigDecimal("2.0");
// repeatedly apply Newton update step until desired precision is achieved
int scale = 10;
while (t.subtract(c.divide(t, scale, RoundingMode.CEILING)).abs().compareTo(epsilon) > 0) {
t = c.divide(t, scale, RoundingMode.CEILING).add(t).divide(two, scale, RoundingMode.CEILING);
}
// print out the estimate of the square root of c
System.out.println(t);
}
但是,如果您只選擇 3 作為舍入比例,您將再次陷入無休止的循環。
因此,在您的情況下,實際上是浮點除法的精度導致了無休止的循環。的乘法epsilon * t只是克服默認浮點運算中舍入精度不足的一個技巧。

TA貢獻1995條經驗 獲得超2個贊
double
具有大約 15 位精度(或 1 到 2^52 或 4.5e15)。當您計算t * epsilon
您需要 1 與1e15/234
可能的比率的誤差double
時,當您使用時,epsilon
您需要 1 與 1 的比率,該比率處于1e15
double 精度的極限,除非它是一個精確值并且錯誤是0
. 例如,試試這個256
,它可能會起作用,但任何不是精確值的東西都可能不起作用。
對任意端點的簡單解決方案是,一旦錯誤從一次迭代到下一次迭代沒有改善,就停止。這將為您提供使用此公式的最準確的解決方案。
添加回答
舉報