三、数值计算常用经典算法:
1.级数计算
级数计算的关键是“描述出通项”,而通项的描述法有两种:一为直接法、二为间接法又称递推法。
直接法的要领是:利用项次直接写出通项式;递推法的要领是:利用前一个(或多个)通项写出后一个通项。
可以用直接法描述通项的级数计算例子有:
(1)1+2+3+4+5+……
(2)1+1/2+1/3+1/4+1/5+……等等。
可以用间接法描述通项的级数计算例子有:
(1)1+1/2+2/3+3/5+5/8+8/13+……
(2)1+1/2!+1/3!+1/4!+1/5!+……等等。
(1)直接法求通项
例1、求1+1/2+1/3+1/4+1/5+……+1/100的和。
main()
{floats;inti;
s=0.0;
for(i=1;i<=100;i++)s=s+1.0/i;
printf("1+1/2+1/3+...+1/100=%fn",s);
}
【解析】程序中加粗部分就是利用项次i的倒数直接描述出每一项,并进行累加。注意:因为i是整数,故分子必须写成1.0的形式!
(2)间接法求通项(即递推法)
例2、计算下列式子前20项的和:1+1/2+2/3+3/5+5/8+8/13+……。
[分析]此题后项的分子是前项的分母,后项的分母是前项分子分母之和。
main()
{floats,fz,fm,t,fz1;inti;
s=1;
fz=1;fm=2;
t=fz/fm;
for(i=2;i<=20;i++)
{s=s+t;
fz1=fz;
fz=fm;
fm=fz1+fm;
t=fz/fm;}
printf("1+1/2+2/3+...=%fn",s);
}
下面举一个通项的一部分用直接法描述,另一部分用递推法描述的级数计算的例子:
例3、计算级数的值,当通项的绝对值小于eps时计算停止。
#include<math.h>
floatg(floatx,floateps);
main()
{floatx,eps;
scanf("%f%f",&x,&eps);
printf("n%f,%fn",x,g(x,eps));
}
floatg(floatx,floateps)
{intn=1;floats,t;
s=1;t=1;
do{t=t*x/(2*n);
s=s+(n*n+1)*t;
n++;}while(fabs(t)>eps);
returns;
}
2.一元非线性方程求根
(1)牛顿迭代法
牛顿迭代法又称牛顿切线法:先任意设定一个与真实的根接近的值x0作为第一次近似根,由x0求出f(x0),过(x0,f(x0))点做f(x)的切线,交x轴于x1,把它作为第二次近似根,再由x1求出f(x1),过(x1,f(x1))点做f(x)的切线,交x轴于x2,……如此继续下去,直到足够接近(比如|x-x0|<1e-6时)真正的根x*为止。
而f'(x0)=f(x0)/(x1-x0)所以x1=x0-f(x0)/f'(x0)
例如,用牛顿迭代法求下列方程在1.5附近的根:2x3-4x2+3x-6=0。
#include"math.h"
main()
{floatx,x0,f,f1;x=1.5;
do{x0=x;
f=2*x0*x0*x0-4*x0*x0+3*x0-6;
f1=6*x0*x0-8*x0+3;
x=x0-f/f1;}while(fabs(x-x0)>=1e-5);
printf("%fn",x);}
(2)二分法
算法要领是:先指定一个区间[x1,x2],如果函数f(x)在此区间是单调变化的,则可以根据f(x1)和f(x2)是否同号来确定方程f(x)=0在区间[x1,x2]内是否有一个实根;如果f(x1)和f(x2)同号,则f(x)在区间[x1,x2]内无实根,要重新改变x1和x2的值。当确定f(x)在区间[x1,x2]内有一个实根后,可采取二分法将[x1,x2]一分为二,再判断在哪一个小区间中有实根。如此不断进行下去,直到小区间足够小为止。
具体算法如下:
(1)输入x1和x2的值。
(2)求f(x1)和f(x2)。
(3)如果f(x1)和f(x2)同号说明在[x1,x2]内无实根,返回步骤(1),重新输入x1和x2的值;若f(x1)和f(x2)不同号,则在区间[x1,x2]内必有一个实根,执行步骤(4)。
(4)求x1和x2的中点:x0=(x1+x2)/2。
(5)求f(x0)。
(6)判断f(x0)与f(x1)是否同号。
①如果同号,则应在[x0,x2]中寻找根,此时x1已不起作用,用x0代替x1,用f(x0)代替f(x1)。
②如果不同号,则应在[x1,x0]中寻找根,此时x2已不起作用,用x0代替x2,用f(x0)代替f(x2)。
(7)判断f(x0)的绝对值是否小于某一指定的值(例如10-5)。若不小于10-5,则返回步骤(4)重复执行步骤(4)、(5)、(6);否则执行步骤(8)。
(8)输出x0的值,它就是所求出的近似根。
例如,用二分法求方程2x3-4x2+3x-6=0在(-10,10)之间的根。
#include"math.h"
main()
{floatx1,x2,x0,fx1,fx2,fx0;
do{printf("Enterx1&x2");
scanf("%f%f",&x1,&x2);
fx1=2*x1*x1*x1-4*x1*x1+3*x1-6;
fx2=2*x2*x2*x2-4*x2*x2+3*x2-6;
}while(fx1*fx2>0);
do{x0=(x1+x2)/2;
fx0=2*x0*x0*x0-4*x0*x0+3*x0-6;
if((fx0*fx1)<0){x2=x0;fx2=fx0;}
else{x1=x0;fx1=fx0;}
}while(fabs(fx0)>1e-5);
printf("%fn",x0);}