《实用计算方法实验报告》
学院名称: 计算机工程学院 专 业: 班 级: 姓 名: 学 号:
成 绩:
2014 年 12月 24日
实用计算方法实验报告
实验目的:
主要针对的是这类问题:
已知f(x)在节点
些节点处的导数的近似值
, …,
处的函数值f(
) , …,f(
), 计算f(x)在这
程序:
引用书P44的求导公式例程
过程记录:
一、 理论依据:
插值型数值微分
先构造出f(x)的插值多项式 的导数。 多项式插值余项:
(x),然后用(x)的导数来代替f(x)
(x)=
两边求导:
+
=
(1)当n=1时,即为等距两点公式。设节点 由上述公式得:
,,他们的步长h=-;
两边再求导得:
因此
(2)当n=2时,即为等距三点公式。设节点
长即为h ;
由上述公式得:
,=+h,=+2h,步
令x =x 0+th ;
两边求导得:
(
- +3
()=
()=(
)=
因此
+3
-
则,利用三点公式求二阶倒数,应将函数再次求导:
+
,=
+h,=
+2h
,
(3)同理,当n=3时,即为等距四点公式。设节点
=
+h,步长即为h ;
求二阶导数
因此
4
2
而求导公式例程的程序皆由此而来;
二、 举出实例
举出y =x 3实例
已知函数y =x 3的函数值表
用两点公式,三点公式,四点公式计算x=1.2处的一阶,二阶导数。 取
,
由两点公式计算: 取 取
,
得
,
得
, 因此在x=1.2处的一阶导数应为4.32,可知
,
得
取 而y=
求导得
步长越长,误差越大。
取,
由三点公式计算:
而
似。
取
,
得
; 则在x=1.2处的二阶导数为7.2,与三点公式所得结果近
由四点公式计算:
1
(2f (1) -5f (1. 1) +4f (1. 2) -f (1. 3)) =16 0. 12
1
(2f (1) -2f (1. 1) +f (1. 2)) =10. 6 f ' ' (1. 1) ≈2
0. 11
(f (1. 1) -2f (1. 2) +f (1. 3)) =5. 2 f ' ' (1. 2) ≈2
0. 11
(-f (1) +4f (1. 1) -5f (1. 2) +2f (1. 3)) =-0. 2 f ' ' (1. 3) ≈0. 12
f ' ' (1) ≈
三、 修改程序(无错误,仅更加完善):
(1)for(k=1;k
{
printf("请输入数据组(x%d,y%d)的数据:\n",k,k); scanf("%f,%f",&x[k],&y[k]); }
进行此操作时,k 的值增加到n ,而后来 printf("请输入(1--4):");
scanf("%d",&k);操作中继续对k 赋值,这里可以考虑将k 换成其他参数比如m ,避免歧义。 printf("请输入(1--4):"); scanf("%d",&m);
(2)在用四点公式计算二阶导数时,由于只有四个参数,所以计算
时,可直接计算出,而利用参数t ,在执行循环时,每次都要进行t 操作,则效率就会下降。 如下:
if(k==4)
for(i=1;i
t=0;
y1[i]=(-(t-2)*y[i]+(3*t-5)*y[i+1]-(3*t-4)*y[i+2] +(t-1)* y[i+3] )/(h*h); t=1;
y1[i+1]=(-(t-2)*y[i]+(3*t-5)*y[i+1]-(3*t-4)*y[i+2] +(t-1)*y[i+3])/(h*h); t=2;
y1[i+2]=(-(t-2)*y[i]+(3*t-5)*y[i+1]-(3*t-4)*y[i+2] +(t-1)*y[i+3] )/(h*h); t=3;
y1[i+3]= (-(t-2)* y[i]+(3*t-5)*y[i+1]-(3*t-4) *y[i+2] +(t-1)* y[i+3] )/(h*h) ; }
改为:
if(m==4)
for(i=1;i
y1[i]=(2*y[i]-5*y[i+1]+4*y[i+2]- y[i+3] )/(h*h); y1[i+1]=( y[i]-2 *y[i+1]+ y[i+2])/(h*h); y1[i+2]=( y[i+1]-2 *y[i+2]+ y[i+3] )/(h*h);
y1[i+3]= (-y[i]+4*y[i+1]-5 *y[i+2]+2*y[i+3] )/(h*h); } 即不使用参数t ,直接计算,省略每次循环时对于系数的计算。
(3)程序有一个瑕疵,那就是只能进行一次操作,如果对于同一组
数据,要比较其通过两点公式和三点公式操作后得到的结果就不太 容易,所以,建议在原来的程序 printf("请输入(1--4):"); scanf("%d",&m); 后方插入
if(m4)
return;
while(m>0&&m
printf("\n\n请输入(1--4):");
scanf("%d",&m); }
这样能够保证,在进行一次操作后,能够再次选择其他选项。
注意:
A.添加如上所示的代码后,要同时更替源程序中的子函数,即每个
case 后方的子函数,要统一,函数中的参数也要统一。
B .输入的数字要是2,3,4的公倍数,才能保证每个case 都能运行,
因为输入的数要是点个数的倍数,才能运行。此项可以参考操作记录中的输入4时的截图,输入4时,因为开始输入的数字是6,所以,有两个数多余,所以程序只能break ,提示结束。
C .由于计算公式的误差均和x i+1-x i =h有关,实际计算时h 越小越好。 D .当插值节点个数大于20时(例如节点的个数是40),只要修改
程序中行:double x[21],y[21],y1[21],h;中的21(为41),即个数为多少,就将数组的大小控制在比个数大一点即可。
四、操作记录(截图):
如图是输入数据为6个时,分别求两点公式一阶导数,三点公式一阶导数,三点公式二阶导数。利用switch 语句,实现一组数据的多重求导,从而方便比较。
由图也可发现两点求一阶导数相对于三点公式求一阶导数来说,三点公式求导更为精确。
因为,6是2和3的倍数,所以,1,2,3选项都可以进行。
由于6不是4的倍数,所以输入数据时,只有第一次循环能够得到y1数组里面的值,而后来,没有数据时,程序错误,所以,输入序号4求四点公式求二阶导数不能运行,直接结束。
如图,四点公式求二阶导数,重新输入4的倍数的数据,应该注意此时不能进行三点公式的计算,因为8不是3的倍数。图中前6个数据与以前的数据一样,只是添加了两组数据,但是也可以明显发现,因为三点公式求二阶导数每三组数据得到的结果一致,就没有四阶公式求二阶导数精确。
结果分析:
(1) 发现的问题:
A . 发现无论哪个求导公式都不能精确得到正确的导数,而且,
相对于两点一阶求导来说,三点一阶求导更为准确,而相对于三点公式求二阶导数来说,四点公式求导更精确。因为在两点公式一阶求导和三点公式二阶求导时,不含参数t ,所以得到的结果相同,而给出的数据,他们的函数值是不同的。 B . 由于步长h=
-, 而在计算时,得到的
等,无论
运用哪一个公式时,都要除以h 或者,所以,要使得到的结果更精确,就要使h 越小。我所选用的步长为1,应该再缩小,也许得到的y 的值更接近结果。
C . 对于同一组数据,能够同时对他运用两点公式,三点公式,
四点公式,必须要使数据的个数成为2, 3, 4的公倍数。数学最讲究的就是精确,除了使步长h降低之外,我们还应该多方比较,所以,一组数据能够同时运用两种公式是必要的。这一点还应该加以改进。
(2) 得出的结论:
拓展延伸: A . 导数在经济学,物理学,数学等学术中应用十分广泛,在未
知给出数据的函数公式时,如何求导成为当务之急。就举在经济学方面的例子:
假设某产品的总成本C (万元)与产量q (万件)之间的函数关系式为C=C(q )=100+4q-0.2+0.01
. 从降低成本角
度来看,继续提高产量是否合适。
此时,边际成本就是公式求导。对于一个公式的决策者而言,
除了要考虑社会效益外,更多考虑的是经营的成果。比如说,降低成本,提高利润等问题。
从小处说,瞬时速度v 是路程s 对于时间t 的导数,我们平时
接触的速度都是平均速度,用总路程除以时间,而对于某个物体在某个时刻的速度不得而知,因此,学习如何求导十分重要。 B . 需要选取的公式还是要根据所给数据的个数来定,是偶数就
用两点公式,是3的倍数就用三点公式,同理,4的时候也是。如果遇到同为2和3的倍数,建议两种方法都尝试来加以比较。
C . 另外,由于题目中要求的数据个数是20以内,所以x数组,
y数组,甚至y1数组的大小是21。如果,当输入数据的量增多时,不要忘记同时扩展x数组,y数组,y1数组的大小
范围比数据的量大稍许。但是,他们的大小不宜大太多,不然
浪费空间。
特殊函数(多项式)求导
上面所述,是未知函数关系式,而根据一组数据求解的过程。
下面将介绍已知函数多项式,从而求解函数的导数,这个过程,较 简单。但是,要注意,要是特殊函数多项式,要是其他函数,他们 的近似求导还需运用上面的例程。 一、程序 (1)多项式求导例程 #include #include void main() { int n; int i; int a[10];
printf("请输入最高指数:"); scanf("%d",&n);
printf("请依次输入多项式的系数:"); for(i=0;i
scanf("%d",p+i); }
printf("函数的多项式为: \n"); printf("y="); for(i=0;i
printf("%dx^%d+",a[i],n-i-1); else
printf("%dx^%d",a[i],n-i-1); }
printf("\n多项式一阶求导结果为:\n"); printf("y="); for(i=0;i
printf("%dx^%d+",a[i]*(n-i-1),n-i-2); else
printf("%dx^%d",a[i]*(n-i-1),n-i-2); }
printf("\b\n"); }
(2)多项式求值例程 #include int main() { int i,n,j ; double x; int a[100] double,sum=0;
scanf("%d%lf",&n,&x); for(i=0;i
for(j=0;j
for(i=0;i
此程序,运行后所得是多项式求导后y =2x 6+4x 5+3x 3+x 所得的
导数的多项式关系式,而,根据这个函数多项式,代入x 的数值就 能够得到每个点处的导数,得到结果较为准确。多项式求导后,每 个x 的前面的系数是原本系数乘以x 的指数,所得结果即为现在的 指数减一后的x 前面的系数。将系数乘以对应的x 的个数,就能得 到x 的值。 例如:
y =2x 8+6x 3+x 求导为:
y =16x 7+18x 2+1x 0 再输入x 的值:x=1; y=35; 三、举例说明
例如,求解y =2x 6+3x 5+4x 3+2x 2+x
因此,求导后的函数关系式为
y =12x 5+15x 4+12x 2+4x +1 当x=0; y=44;
若要求多个点的导数,则将x 定义为数组 四、 操作记录 操作步骤
1.根据提示输入最高次数的指数的值,从而确定要进行多少次循 环。
2.根据提示输入每个x 前面的系数值,从而为后来计算后来的x 前面的系数准备。
3.输出所得的多项式,看对比起来是否准确。
4.根据理论依据,计算求导后的多项式,同时,在纸上也可以先 求出导数。
5.根据提示输入x 的值求解出在此处的导数值
6.若有多个点,则定义为数组,依次输入x 的值,从而求解每个 求导后的导数值。
7.此程序求出的是函数的一阶导数,若要求二阶导数,则在一开 始添加一个循环,求一阶导数即循环一次,若求二阶导数,则 两次。 操作截图
(1)求多项式求导的关系式
(2)求多项式的值
注意:
(1)此程序仅限于已知函数多项式时,求导后的多项式的函数关系式, 若未知函数关系式时,如计算y e x 的导数时,这样求导,就会 现在的水平,还不能总结出精确的适用于所有的函数的导数求解 方法,所以,编制程序以及使用程序解决问题时,要理解程序, 了解程序的使用范围。
(2) if(i
printf("%dx^%d+",p[i]*(n-i-1),n-i-2); else
printf("%dx^%d",p[i]*(n-i-1),n-i-2);
有些人可能觉得这个步骤没有必要,但是,这个步骤也是关键, 如果没有此步,所得的函数关系式后面就会多一个加号,但是, 仅仅将循环的判断条件变为i
(3)多项式求导例程是计算a0+a1*x+a2*x*x+a3*x*x*x+......+an*x*x*...*x 的值,在合并两个程序时,应该考虑将存放系数数组的顺序倒置,或 者,执行循环时,将i 从大到小计算。
《实用计算方法实验报告》
学院名称: 计算机工程学院 专 业: 班 级: 姓 名: 学 号:
成 绩:
2014 年 12月 24日
实用计算方法实验报告
实验目的:
主要针对的是这类问题:
已知f(x)在节点
些节点处的导数的近似值
, …,
处的函数值f(
) , …,f(
), 计算f(x)在这
程序:
引用书P44的求导公式例程
过程记录:
一、 理论依据:
插值型数值微分
先构造出f(x)的插值多项式 的导数。 多项式插值余项:
(x),然后用(x)的导数来代替f(x)
(x)=
两边求导:
+
=
(1)当n=1时,即为等距两点公式。设节点 由上述公式得:
,,他们的步长h=-;
两边再求导得:
因此
(2)当n=2时,即为等距三点公式。设节点
长即为h ;
由上述公式得:
,=+h,=+2h,步
令x =x 0+th ;
两边求导得:
(
- +3
()=
()=(
)=
因此
+3
-
则,利用三点公式求二阶倒数,应将函数再次求导:
+
,=
+h,=
+2h
,
(3)同理,当n=3时,即为等距四点公式。设节点
=
+h,步长即为h ;
求二阶导数
因此
4
2
而求导公式例程的程序皆由此而来;
二、 举出实例
举出y =x 3实例
已知函数y =x 3的函数值表
用两点公式,三点公式,四点公式计算x=1.2处的一阶,二阶导数。 取
,
由两点公式计算: 取 取
,
得
,
得
, 因此在x=1.2处的一阶导数应为4.32,可知
,
得
取 而y=
求导得
步长越长,误差越大。
取,
由三点公式计算:
而
似。
取
,
得
; 则在x=1.2处的二阶导数为7.2,与三点公式所得结果近
由四点公式计算:
1
(2f (1) -5f (1. 1) +4f (1. 2) -f (1. 3)) =16 0. 12
1
(2f (1) -2f (1. 1) +f (1. 2)) =10. 6 f ' ' (1. 1) ≈2
0. 11
(f (1. 1) -2f (1. 2) +f (1. 3)) =5. 2 f ' ' (1. 2) ≈2
0. 11
(-f (1) +4f (1. 1) -5f (1. 2) +2f (1. 3)) =-0. 2 f ' ' (1. 3) ≈0. 12
f ' ' (1) ≈
三、 修改程序(无错误,仅更加完善):
(1)for(k=1;k
{
printf("请输入数据组(x%d,y%d)的数据:\n",k,k); scanf("%f,%f",&x[k],&y[k]); }
进行此操作时,k 的值增加到n ,而后来 printf("请输入(1--4):");
scanf("%d",&k);操作中继续对k 赋值,这里可以考虑将k 换成其他参数比如m ,避免歧义。 printf("请输入(1--4):"); scanf("%d",&m);
(2)在用四点公式计算二阶导数时,由于只有四个参数,所以计算
时,可直接计算出,而利用参数t ,在执行循环时,每次都要进行t 操作,则效率就会下降。 如下:
if(k==4)
for(i=1;i
t=0;
y1[i]=(-(t-2)*y[i]+(3*t-5)*y[i+1]-(3*t-4)*y[i+2] +(t-1)* y[i+3] )/(h*h); t=1;
y1[i+1]=(-(t-2)*y[i]+(3*t-5)*y[i+1]-(3*t-4)*y[i+2] +(t-1)*y[i+3])/(h*h); t=2;
y1[i+2]=(-(t-2)*y[i]+(3*t-5)*y[i+1]-(3*t-4)*y[i+2] +(t-1)*y[i+3] )/(h*h); t=3;
y1[i+3]= (-(t-2)* y[i]+(3*t-5)*y[i+1]-(3*t-4) *y[i+2] +(t-1)* y[i+3] )/(h*h) ; }
改为:
if(m==4)
for(i=1;i
y1[i]=(2*y[i]-5*y[i+1]+4*y[i+2]- y[i+3] )/(h*h); y1[i+1]=( y[i]-2 *y[i+1]+ y[i+2])/(h*h); y1[i+2]=( y[i+1]-2 *y[i+2]+ y[i+3] )/(h*h);
y1[i+3]= (-y[i]+4*y[i+1]-5 *y[i+2]+2*y[i+3] )/(h*h); } 即不使用参数t ,直接计算,省略每次循环时对于系数的计算。
(3)程序有一个瑕疵,那就是只能进行一次操作,如果对于同一组
数据,要比较其通过两点公式和三点公式操作后得到的结果就不太 容易,所以,建议在原来的程序 printf("请输入(1--4):"); scanf("%d",&m); 后方插入
if(m4)
return;
while(m>0&&m
printf("\n\n请输入(1--4):");
scanf("%d",&m); }
这样能够保证,在进行一次操作后,能够再次选择其他选项。
注意:
A.添加如上所示的代码后,要同时更替源程序中的子函数,即每个
case 后方的子函数,要统一,函数中的参数也要统一。
B .输入的数字要是2,3,4的公倍数,才能保证每个case 都能运行,
因为输入的数要是点个数的倍数,才能运行。此项可以参考操作记录中的输入4时的截图,输入4时,因为开始输入的数字是6,所以,有两个数多余,所以程序只能break ,提示结束。
C .由于计算公式的误差均和x i+1-x i =h有关,实际计算时h 越小越好。 D .当插值节点个数大于20时(例如节点的个数是40),只要修改
程序中行:double x[21],y[21],y1[21],h;中的21(为41),即个数为多少,就将数组的大小控制在比个数大一点即可。
四、操作记录(截图):
如图是输入数据为6个时,分别求两点公式一阶导数,三点公式一阶导数,三点公式二阶导数。利用switch 语句,实现一组数据的多重求导,从而方便比较。
由图也可发现两点求一阶导数相对于三点公式求一阶导数来说,三点公式求导更为精确。
因为,6是2和3的倍数,所以,1,2,3选项都可以进行。
由于6不是4的倍数,所以输入数据时,只有第一次循环能够得到y1数组里面的值,而后来,没有数据时,程序错误,所以,输入序号4求四点公式求二阶导数不能运行,直接结束。
如图,四点公式求二阶导数,重新输入4的倍数的数据,应该注意此时不能进行三点公式的计算,因为8不是3的倍数。图中前6个数据与以前的数据一样,只是添加了两组数据,但是也可以明显发现,因为三点公式求二阶导数每三组数据得到的结果一致,就没有四阶公式求二阶导数精确。
结果分析:
(1) 发现的问题:
A . 发现无论哪个求导公式都不能精确得到正确的导数,而且,
相对于两点一阶求导来说,三点一阶求导更为准确,而相对于三点公式求二阶导数来说,四点公式求导更精确。因为在两点公式一阶求导和三点公式二阶求导时,不含参数t ,所以得到的结果相同,而给出的数据,他们的函数值是不同的。 B . 由于步长h=
-, 而在计算时,得到的
等,无论
运用哪一个公式时,都要除以h 或者,所以,要使得到的结果更精确,就要使h 越小。我所选用的步长为1,应该再缩小,也许得到的y 的值更接近结果。
C . 对于同一组数据,能够同时对他运用两点公式,三点公式,
四点公式,必须要使数据的个数成为2, 3, 4的公倍数。数学最讲究的就是精确,除了使步长h降低之外,我们还应该多方比较,所以,一组数据能够同时运用两种公式是必要的。这一点还应该加以改进。
(2) 得出的结论:
拓展延伸: A . 导数在经济学,物理学,数学等学术中应用十分广泛,在未
知给出数据的函数公式时,如何求导成为当务之急。就举在经济学方面的例子:
假设某产品的总成本C (万元)与产量q (万件)之间的函数关系式为C=C(q )=100+4q-0.2+0.01
. 从降低成本角
度来看,继续提高产量是否合适。
此时,边际成本就是公式求导。对于一个公式的决策者而言,
除了要考虑社会效益外,更多考虑的是经营的成果。比如说,降低成本,提高利润等问题。
从小处说,瞬时速度v 是路程s 对于时间t 的导数,我们平时
接触的速度都是平均速度,用总路程除以时间,而对于某个物体在某个时刻的速度不得而知,因此,学习如何求导十分重要。 B . 需要选取的公式还是要根据所给数据的个数来定,是偶数就
用两点公式,是3的倍数就用三点公式,同理,4的时候也是。如果遇到同为2和3的倍数,建议两种方法都尝试来加以比较。
C . 另外,由于题目中要求的数据个数是20以内,所以x数组,
y数组,甚至y1数组的大小是21。如果,当输入数据的量增多时,不要忘记同时扩展x数组,y数组,y1数组的大小
范围比数据的量大稍许。但是,他们的大小不宜大太多,不然
浪费空间。
特殊函数(多项式)求导
上面所述,是未知函数关系式,而根据一组数据求解的过程。
下面将介绍已知函数多项式,从而求解函数的导数,这个过程,较 简单。但是,要注意,要是特殊函数多项式,要是其他函数,他们 的近似求导还需运用上面的例程。 一、程序 (1)多项式求导例程 #include #include void main() { int n; int i; int a[10];
printf("请输入最高指数:"); scanf("%d",&n);
printf("请依次输入多项式的系数:"); for(i=0;i
scanf("%d",p+i); }
printf("函数的多项式为: \n"); printf("y="); for(i=0;i
printf("%dx^%d+",a[i],n-i-1); else
printf("%dx^%d",a[i],n-i-1); }
printf("\n多项式一阶求导结果为:\n"); printf("y="); for(i=0;i
printf("%dx^%d+",a[i]*(n-i-1),n-i-2); else
printf("%dx^%d",a[i]*(n-i-1),n-i-2); }
printf("\b\n"); }
(2)多项式求值例程 #include int main() { int i,n,j ; double x; int a[100] double,sum=0;
scanf("%d%lf",&n,&x); for(i=0;i
for(j=0;j
for(i=0;i
此程序,运行后所得是多项式求导后y =2x 6+4x 5+3x 3+x 所得的
导数的多项式关系式,而,根据这个函数多项式,代入x 的数值就 能够得到每个点处的导数,得到结果较为准确。多项式求导后,每 个x 的前面的系数是原本系数乘以x 的指数,所得结果即为现在的 指数减一后的x 前面的系数。将系数乘以对应的x 的个数,就能得 到x 的值。 例如:
y =2x 8+6x 3+x 求导为:
y =16x 7+18x 2+1x 0 再输入x 的值:x=1; y=35; 三、举例说明
例如,求解y =2x 6+3x 5+4x 3+2x 2+x
因此,求导后的函数关系式为
y =12x 5+15x 4+12x 2+4x +1 当x=0; y=44;
若要求多个点的导数,则将x 定义为数组 四、 操作记录 操作步骤
1.根据提示输入最高次数的指数的值,从而确定要进行多少次循 环。
2.根据提示输入每个x 前面的系数值,从而为后来计算后来的x 前面的系数准备。
3.输出所得的多项式,看对比起来是否准确。
4.根据理论依据,计算求导后的多项式,同时,在纸上也可以先 求出导数。
5.根据提示输入x 的值求解出在此处的导数值
6.若有多个点,则定义为数组,依次输入x 的值,从而求解每个 求导后的导数值。
7.此程序求出的是函数的一阶导数,若要求二阶导数,则在一开 始添加一个循环,求一阶导数即循环一次,若求二阶导数,则 两次。 操作截图
(1)求多项式求导的关系式
(2)求多项式的值
注意:
(1)此程序仅限于已知函数多项式时,求导后的多项式的函数关系式, 若未知函数关系式时,如计算y e x 的导数时,这样求导,就会 现在的水平,还不能总结出精确的适用于所有的函数的导数求解 方法,所以,编制程序以及使用程序解决问题时,要理解程序, 了解程序的使用范围。
(2) if(i
printf("%dx^%d+",p[i]*(n-i-1),n-i-2); else
printf("%dx^%d",p[i]*(n-i-1),n-i-2);
有些人可能觉得这个步骤没有必要,但是,这个步骤也是关键, 如果没有此步,所得的函数关系式后面就会多一个加号,但是, 仅仅将循环的判断条件变为i
(3)多项式求导例程是计算a0+a1*x+a2*x*x+a3*x*x*x+......+an*x*x*...*x 的值,在合并两个程序时,应该考虑将存放系数数组的顺序倒置,或 者,执行循环时,将i 从大到小计算。