私は、ニュートン・ラフソン法を使って数値の平方根を計算するために以下の関数を持っています。1.0E21と1.0E23の平方根を計算するとき、ニュートンラフソン法が収束しないのはなぜですか?
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);
}
、ここでは(GCC 4.8.4を使用して、64ビットのLinux上に構築された)出力です:
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'です。これらの2つの数値は16桁離れており、これは「倍精度」の精度の限界を超えています。私はあなたに「1e25」と幸運にも恵まれていると仮定します。 – user3386109
これは浮動小数点精度の問題です。絶対的なものではなく、相対的なものになるように、あなたの 'tolerance 'を修正する必要があります。例えば、あなたのターゲット番号が '1e11'ならば、仮数は' 1e-6'のデルタを収容するのに十分ではないので、公差は事実上ゼロです。つまり、1e11 + 1e6 == 1e11となる。 –
@ user3386109、ちょうどキックのために、1.0E27でも試してみました。奇妙な。 –