如果有时间,我会渐渐的把数值分析的实验写完。总共8个实验,今天写的是方程求根里的通过牛顿迭代法求一元多次方程的根。
若函数f(x)连续可导,将f(x)在点x_k 处进行一阶泰勒展开,有:
令 f(x) = 0, 当f'(x_k) != 0 时,有:
于是,我们可以得到迭代公式:
关于牛顿迭代法了解到这就行了, 既然有了迭代公式,最主要的是如何通过编程实现它。
一.输入
既然是解方程,方程是必须输入的。但方程不可能原样的输入,所以我们要找到我们所需要的 必要信息:各项的系数、最高次幂、以及我们手动取的一个近似值
系数和当前项的幂可以通过一个数组来解决。数组是种有序的线性结构,元素在里面是顺序存放的,所以从高次到低次顺序输入就可以了。为了方便,即使系数是0,0也需要输入,不能省略。输入最高次幂是为了分配数组空间和之后的计算服务的。
二.计算f(x) 、f`(x)
牛顿迭代法的关键就是迭代公式,迭代公式的关键就是计算函数值和函数导数的值。
这里很简单,理清思路就可以了:
// f(x)、f`(x)
double f(double x, double *a, int n){
double res = 0;
int i;
for(i = 0; i <= n; i++){
res += a[i] * pow(x, n - i);
}
return res;
}
double ff(double x, double *a, int n){
double res = 0;
int i;
for(i = 0; i <= n; i++){
res += a[i] * (n - i) * (n - i - 1 >= 0 ? pow(x, n - i - 1) : 0);
}
return res;
}
注意一下f`(x)的计算,如果套用前面的求导方法就会出错。最后常数项应该单独处理,常数项的导数为0。
三.不断迭代到合适的精度
迭代过程就是一个不断逼近准确根的过程,所以在精度已经足够好了,也就是说 x_k 和 x_k + 1 差值足够小的时候,结束迭代就可以了。
// 初始时令last != x_k, 并保存x的值
x_first = (last = x_k + 1) - 1;
// 前后两次差值 < 0.00001 就结束循环
while(fabs(x_k - last) > 0.00001){
last = x_k;
x_k = last - f(last, a, n) / ff(last, a, n);
}
四.例题 && 测试
图片来自 《计算方法(李桂成)》
测试
五.完整代码(C语言)
C代码:
// 牛顿迭代法求一元n次方程根
#include
#include
#include
// f(x)、f`(x)
double f(double x, double *a, int n){
double res = 0;
int i;
for(i = 0; i <= n; i++){
res += a[i] * pow(x, n - i);
}
return res;
}
double ff(double x, double *a, int n){
double res = 0;
int i;
for(i = 0; i <= n; i++){
res += a[i] * (n - i) * (n - i - 1 >= 0 ? pow(x, n - i - 1) : 0);
}
return res;
}
int main(){
// n次幂、存储各项系数的数组a、循环变量i
int n;
double *a;
int i;
// x_k
double x_k, last, x_first;
// 输入n次幂
printf("输入方程的次幂:");
scanf("%d", &n);
// 为a分配空间
a = (double*) malloc(sizeof(double) * (n + 1));
// 输入各项系数
printf("输入方程各项系数(从高次到低次):");
for(i = 0; i <= n ; i++){
scanf("%lf", a + i);
}
// 开始秀
printf("输入x的初始值:");
scanf("%lf", &x_k);
// 初始时令last != x_k, 并保存x的值
x_first = (last = x_k + 1) - 1;
// 前后两次差值 < 0.00001 就结束循环
while(fabs(x_k - last) > 0.00001){
last = x_k;
x_k = last - f(last, a, n) / ff(last, a, n);
}
// 输出求得的根
printf("方程在x = %.1lf 附近的根为:%.5lf", x_first, x_k);
// end
getchar();
return 0;
}