牛頓迭代法:介紹、原理與運用
介紹
牛頓迭代法是一個可以求一個任意函數的零點的工具。它比二分法快得多。
公式是:x=a-f(a)/f'(a)。其中a是猜測值,x是新的猜測值。不斷迭代,f(x)就越來越接近0。
原理
我們將f(x)做泰勒一階展開:f(x)∼f(a)+(x-a)f'(a)。
| 令 | f(x) | = | 0 |
| ∴ | f(a)+(x-a)f'(a) | = | 0 |
| ∴ | f(a)+xf'(a)-af'(a) | = | 0 |
| ∴ | xf'(a) | = | af'(a)-f(a) |
| ∴ | x | = | a-f(a)/f'(a) |
實例:牛頓迭代法求√2的近似值
| ∵ | x = √2 |
| ∴ | x2 = 2 |
| ∴ | x2 -2 = 0 |
令f(x)=方程左邊,則f(x)∼0↔x∼√2。
f'(x) = 2x。於是可以得到迭代公式:
| x | |
| = | a-f(a)/f'(a) |
| = | a-(a2-2)/(2a) |
| = | a-a/2+1/a |
| = | a/2+1/a |
代碼如下(要求誤差小於1e-6):
#include <stdio.h>
#include <math.h>
int main(int argc, char const *argv[])
{
double a = 2.0;
double expect_error = 0.000001;
double x;
double actual_error;
unsigned iteration_count = 0;
do {
if (a == 0.0) a = 0.1; /* 避免0做分母 */
x = a/2 + 1/a;
actual_error = fabs(2 - x*x);
a = x;
++iteration_count;
printf("%d\t%.9f\t%.9f\n", iteration_count, a, actual_error);
} while (actual_error >= expect_error);
return 0;
}
輸出:
1 1.500000000 0.250000000 2 1.416666667 0.006944444 3 1.414215686 0.000006007 4 1.414213562 0.000000000
迭代了4次。用二分法呢?
1 1.500000000 0.250000000 2 1.250000000 0.437500000 3 1.375000000 0.109375000 4 1.437500000 0.066406250 5 1.406250000 0.022460938 6 1.421875000 0.021728516 7 1.414062500 0.000427246 8 1.417968750 0.010635376 9 1.416015625 0.005100250 10 1.415039062 0.002335548 11 1.414550781 0.000953913 12 1.414306641 0.000263274 13 1.414184570 0.000082001 14 1.414245605 0.000090633 15 1.414215088 0.000004315 16 1.414199829 0.000038843 17 1.414207458 0.000017264 18 1.414211273 0.000006475 19 1.414213181 0.000001080 20 1.414214134 0.000001617 21 1.414213657 0.000000269
二分法需要21次,而且精度還要差3位。
是不是二分法就一定比牛頓法慢呢?我測試了一下,發現不是的:
圖中x軸是被開方的數,y軸為牛頓法、二分法開方這個數所用的迭代次數。
可以看出,某些時候二分法是比牛頓法快的。但是牛頓法的迭代次數要穩定一些。
