我有以下函數用於計算使用Newton-Raphson方法的數字的平方根。當計算1.0E21和1.0E23的平方根時,爲什麼Newton-Raphson方法不會收斂?
double get_dx(double y, double x)
{
return (x*x - y)/(2*x);
}
double my_sqrt(double y, double initial)
{
double tolerance = 1.0E-6;
double x = initial;
double dx;
int iteration_count = 0;
while (iteration_count < 100 &&
fabs(dx = get_dx(y, x)) > tolerance)
{
x -= dx;
++iteration_count;
if (iteration_count > 90)
{
printf("Iteration number: %d, dx: %lf\n", iteration_count, dx);
}
}
if (iteration_count < 100)
{
printf("Got the result to converge in %d iterations.\n", iteration_count);
}
else
{
printf("Could not get the result to converge.\n");
}
return x;
}
它們適用於大多數數字。但是,當y
爲1.0E21
和1.0E23
時,它們不收斂。可能還有其他數字,我還不知道,但功能不會收斂。開始使用的東西 -
y*0.5
:我的初始值進行測試。
1.0E10
- 最終結果附近的數字。sqrt(y)+1.0
- 顯然,與最終答案非常接近。
在所有這些情況下,1.0E21
和1.0E23
的函數均未收斂。我嘗試了一個較低的號碼,1.0E19
和更高的號碼,1.0E25
。它們都不是問題。
這裏有一個完整的程序:
#include <stdio.h>
#include <math.h>
double get_dx(double y, double x)
{
return (x*x - y)/(2*x);
}
double my_sqrt(double y, double initial)
{
double tolerance = 1.0E-6;
double x = initial;
double dx;
int iteration_count = 0;
while (iteration_count < 100 &&
fabs(dx = get_dx(y, x)) > tolerance)
{
x -= dx;
++iteration_count;
if (iteration_count > 90)
{
printf("Iteration number: %d, dx: %lf\n", iteration_count, dx);
}
}
if (iteration_count < 100)
{
printf("Got the result to converge in %d iterations.\n", iteration_count);
}
else
{
printf("Could not get the result to converge.\n");
}
return x;
}
void test(double y)
{
double ans = my_sqrt(y, 0.5*y);
printf("sqrt of %lg: %lg\n\n", y, ans);
ans = my_sqrt(y, 1.0E10);
printf("sqrt of %lg: %lg\n\n", y, ans);
ans = my_sqrt(y, sqrt(y) + 1.0);
printf("sqrt of %lg: %lg\n\n", y, ans);
}
int main()
{
test(1.0E21);
test(1.0E23);
test(1.0E19);
test(1.0E25);
}
和這裏的輸出(建立在64位Linux,用gcc 4.8.4):
Iteration number: 91, dx: -0.000002
Iteration number: 92, dx: 0.000002
Iteration number: 93, dx: -0.000002
Iteration number: 94, dx: 0.000002
Iteration number: 95, dx: -0.000002
Iteration number: 96, dx: 0.000002
Iteration number: 97, dx: -0.000002
Iteration number: 98, dx: 0.000002
Iteration number: 99, dx: -0.000002
Iteration number: 100, dx: 0.000002
Could not get the result to converge.
sqrt of 1e+21: 3.16228e+10
Iteration number: 91, dx: 0.000002
Iteration number: 92, dx: -0.000002
Iteration number: 93, dx: 0.000002
Iteration number: 94, dx: -0.000002
Iteration number: 95, dx: 0.000002
Iteration number: 96, dx: -0.000002
Iteration number: 97, dx: 0.000002
Iteration number: 98, dx: -0.000002
Iteration number: 99, dx: 0.000002
Iteration number: 100, dx: -0.000002
Could not get the result to converge.
sqrt of 1e+21: 3.16228e+10
Iteration number: 91, dx: 0.000002
Iteration number: 92, dx: -0.000002
Iteration number: 93, dx: 0.000002
Iteration number: 94, dx: -0.000002
Iteration number: 95, dx: 0.000002
Iteration number: 96, dx: -0.000002
Iteration number: 97, dx: 0.000002
Iteration number: 98, dx: -0.000002
Iteration number: 99, dx: 0.000002
Iteration number: 100, dx: -0.000002
Could not get the result to converge.
sqrt of 1e+21: 3.16228e+10
Iteration number: 91, dx: 0.000027
Iteration number: 92, dx: 0.000027
Iteration number: 93, dx: 0.000027
Iteration number: 94, dx: 0.000027
Iteration number: 95, dx: 0.000027
Iteration number: 96, dx: 0.000027
Iteration number: 97, dx: 0.000027
Iteration number: 98, dx: 0.000027
Iteration number: 99, dx: 0.000027
Iteration number: 100, dx: 0.000027
Could not get the result to converge.
sqrt of 1e+23: 3.16228e+11
Iteration number: 91, dx: -0.000027
Iteration number: 92, dx: -0.000027
Iteration number: 93, dx: -0.000027
Iteration number: 94, dx: -0.000027
Iteration number: 95, dx: -0.000027
Iteration number: 96, dx: -0.000027
Iteration number: 97, dx: -0.000027
Iteration number: 98, dx: -0.000027
Iteration number: 99, dx: -0.000027
Iteration number: 100, dx: -0.000027
Could not get the result to converge.
sqrt of 1e+23: 3.16228e+11
Iteration number: 91, dx: 0.000027
Iteration number: 92, dx: 0.000027
Iteration number: 93, dx: 0.000027
Iteration number: 94, dx: 0.000027
Iteration number: 95, dx: 0.000027
Iteration number: 96, dx: 0.000027
Iteration number: 97, dx: 0.000027
Iteration number: 98, dx: 0.000027
Iteration number: 99, dx: 0.000027
Iteration number: 100, dx: 0.000027
Could not get the result to converge.
sqrt of 1e+23: 3.16228e+11
Got the result to converge in 35 iterations.
sqrt of 1e+19: 3.16228e+09
Got the result to converge in 6 iterations.
sqrt of 1e+19: 3.16228e+09
Got the result to converge in 1 iterations.
sqrt of 1e+19: 3.16228e+09
Got the result to converge in 45 iterations.
sqrt of 1e+25: 3.16228e+12
Got the result to converge in 13 iterations.
sqrt of 1e+25: 3.16228e+12
Got the result to converge in 1 iterations.
sqrt of 1e+25: 3.16228e+12
任何人都可以解釋爲什麼上面的功能不要」 t收斂爲1.0E21
和1.0E23
?
您尋求的值是'3.2e10',容差爲1e-6。這兩個數字相差16個數量級,這擴大了「雙」的精度極限。我假設你剛剛用'1e25'獲得了幸運。 – user3386109
這是一個浮點精度問題。你需要修正你的'寬容',以便它是相對的而不是絕對的。例如,如果您的目標數字是'1e11',那麼由於尾數不足以容納「1e-6」的增量,容差實際上爲零。換句話說,'1e11 + 1e6 == 1e11'。 –
@ user3386109,只是爲了踢球,我也用1.0E27試了一下,並且它的功能相互銜接。奇怪。 –