1
第十四讲 编程例题
2
求定积分
1、用梯形公式计算面积的近似值。
( ( ) ( ) )2ba f a f b? ?面积=
这样计算面积误差太大。
a b
f(a )
f(b)
x
y
b - a
3
2、改进:将区间 b-a划分成 2n等分。用变步长的梯形
法,定义 Tn为将积分区间 n等分时求出的近似面积。
1
0
2
( 1 )
1
1 11
1
( 2 )
( ( ) ( ) )
2
()
2 2 2
1
()
2 2 2
n
n
k
k
n
n
ba
T f a f b
h b a
T hh
T f x
n
T hh
T f a
?
?
?
?
??
? ? ?
?
? ? ?
?
n
2n
1
当n=1时,



当时
4
a b
f ( x 1+h/ 2)
x
y
h/2 h/2
5
( 1)为按公式算出的面积的二分之一;
( 2)为等分中线的函数值 f(x1+h/2)与 h的乘积,得出
面积的二分之一。 1
2
0
2
2 2
2
2 22
22
( 3 )
,
()
2 2 2
1
3
[ ( ) ( ) ]
2 2 2 2
n
nk
k
n
n
TT
T hh
T f x
n
T hh
T f a f a h
?
?
? ? ?
?
? ? ? ? ?
?
n
2
2n
1
当n = 2 时,
当时
6
( 3)代表面积
21
2
2
2
2 1
2
2
0
2
2
11
()
22
()
2
3
()
2
3
* [ ( ) ( ) ]
22
( ( 0.5 ) * )
2
n
n
k
k
ac de e f g
ab
h h b a
h
ac f a
e f f a h
h
T h f a f a h
h
f x k h
b
?
?
? ? ?
?
?
? ? ? ?
??
?
解释如下:将 区间分成两段
积分面积用 + 来近似
的长度取
的长度取
这两块的面积之和为
再取一半就
矩形 矩形

7
3、用辛普生公式计算积分的近似值
22
2
2
2
3
0
1
( 4 )
3
2,/ 2
1
n n n
nn
x
I T T
II
n n h h
ex
I dx
x
?
??
??
? ?? ? ??
?
?
?
?
当 认为达到了近似要求。
如未达此精度要求,则让
例:求定积分
8
#include <stdio.h> // 预编译命令
#include <math.h> // 预编译命令,数学函数
double f(double x); // 定义被调用函数 f
void main() // 主函数
{ // 主程序开始
int k,n=1; // 声明整型变量 k,n,并初始化 n
double x,x1=0,x2=2; // 声明双精度变量 x,和 x1,x2
double s,h,tn,t2n,In,I2n;// 声明计算中使用的中间变量
const double eps=1e-6;// 声明双精度变量 eps作为阈值
// 计算 n=1时的 tn和 In,为便于编程
// 分别将它们赋给 t2n和 I2n
h=x2-x1;
t2n=I2n=(h*(f(x1)+f(x2)))/2;
printf("第一次近似计算梯形面积值为 %lf\n",t2n);
In=0;
9
while(fabs(I2n-In)>=eps)//当型循环,精度未达要求则继续
{ // 循环体开始,
// 将上一次计算结果转存入 tn和 In
tn=t2n;
In=I2n;
// 计算 k从 0至 n-1,f(x1+(k+0.5)*h)的和
s=0.0; // 求和变量 s清零
for(k=0;k<n;k=k+1) // 循环求和
{ // 循环体开始
x=x1+(k+0.5)*h;
s=s+f(x);
} // 循环体结束
// 计算 t2n和 I2n
t2n=(tn+h*s)/2.0;
I2n=(4*t2n-tn)/3.0;
10
// 更新 n和 h,用于下一次计算
n=2*n;
h=h/2;
} // 循环体结束
printf("积分值为 %lf\n",I2n); // 输出结果
} // 主函数结束
double f(double x) // 被调用函数 f,用于计算积分项
{ // 函数体开始
// 计算并返回积分项
return ( (exp(x)+x*x)/(1+x*x*x));
} // 函数体结束
运行结果:第一次近似计算提醒面积值为 2.265451
积分值为 3.138948
11
while(fabs(I2n-In)>=eps)//当型循环,精度未达要求则继续
{ // 循环体开始,
// 将上一次计算结果转存入 tn和 In
tn=t2n;
In=I2n;
// 计算 k从 0至 n-1,f(x1+(k+0.5)*h)的和
s=0.0; // 求和变量 s清零
for(k=0;k<n;k=k+1) // 循环求和
{ // 循环体开始
x=x1+(k+0.5)*h;
s=s+f(x);
} // 循环体结束
// 计算 t2n和 I2n
t2n=(tn+h*s)/2.0;
I2n=(4*t2n-tn)/3.0;
12
随机数
说明,
1、要产生随机数需要在预编译中加入库函数
#include <stdlib.h>
2,rand()是产生随机数的函数,它可生成 0至 32767的
整数
3,最大随机数为 RAND_MAX,值为 32767
4,产生随机数需要设置种子
srand((unsigned)time(NULL));
因为时间每分每秒不同,第一个随机数就不会固
定。你可以做试验,如去掉这条,产生十个随机数,
每次都会是一样的。
13
产生的随机数,
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
加上这条之后,你再观察,每一次出的十个数都不同。
14
#include <stdio.h> // 预编译命令
#include <math.h> // 预编译命令
#include <stdlib.h> // 预编译命令
void main(void) // 主函数
{ // 主函数开始
int k; // 定义整型变量 k
srand( (unsigned)time(NULL)); //设置
for(k=0;k<10;k=k+1) //循环
{
//输出随机小数
printf(“%f \n",(float)rand()/RAND_MAX);
}
//输出最大随机数
printf(" 最大随机数为 %d\n",RAND_MAX);
} // 主函数结束
下面的程序是产生十个小数(随机函数 4.c)
15
1、用 rand() / RAND_MAX 来产生大于 0而小于 1的
小数。
2、因为 rand()是整型数,RAND_MAX是整型常数,
两者相除,如不作特殊处理得不出小数,只能为 0。
因为被除数小于除数。因此需要强制转换数据类型,
在除式前加 (float),即
(float) rand() / RAND_MAX
说 明
16
例:求 π的近似值。
如右图,正方形的面积 A=1; 1/4圆的面积 B= π /4。 我们
想象有一个容器在正方形中夹有一个极薄的圆弧隔板。
下小雨时搬至屋外,经一定时间后,称 1/4圆的容器内的
水重 C,与作为一个整体的正方形中的水重 D。 C与 D之
比应该等于 B与 A之比,

可得
伪随机数的应用 ——蒙特卡罗法求几何面积
CB
DA?;44 CCDD? ???
1 x
y
1
0
17
我们让计算机产生伪随机数 x和 y,让 x的值的范围在 0~
1之间;让 y的值的范围也在 0~ 1之间,模拟雨点落在正
方形中,当然会有的雨点落在 1/4圆中,数以百万计雨点
可以累计得到 C和 D,从而上述公式算出 π的近似值。这
里关键是落入扇形区的判据,
如果满足了上述条件,则让 C=C+1。
参考程序见“随机函数 1.c”
22 1xy??
18
#include <stdio.h> // 预编译命令
#include <math.h> // 预编译命令
#include <stdlib.h> // 预编译命令
void main(void) // 主函数
{ // 主函数开始
long k,c=0,d=0; // 定义长整型变量
float pai,x,y; // 定义浮点类型变量
srand( (unsigned)time(NULL));// 设置
for(k=1;k<=100000000;k=k+1)// 循环
{ // 循环体开始
d=d+1; // 累加正方形中落入的一个雨点
x=(float)rand()/32767; // 雨点在 x方向的位置
y=(float)rand()/32767; // 雨点在 y方向的位置
if(sqrt(x*x+y*y)<=1)
c=c+1; // 累加扇形中落入的一个雨

}
pai=4.0*(float)c/d; // 计算 pai的值
printf("pai= %f\n",pai); // 输出 pai的值
} // 主函数结束
19
下面可演化为计算图形的面积。如图所示计算有阴影
线的图形的面积,乍看似乎有些难,但仔细分析即可
在上面程序的基础上来做了。
1 x
y
1
22
1xy ??
22
( 1 ) 1xy? ? ?
从思路上考
虑落在阴影这块面
积上的雨点数 g与
落在正方形整体上
的雨点数 d的比就
是这块面积 s的近
似值。
20
此题的关键是如何判断雨点是落在阴影线的区域内。这
就要用到解析几何的知识:对于以原点 x=0,y=0为圆心,
半径为 1的圆弧,阴影线中的每个点应满足
对于以 x=1,y=0为圆心的圆弧,阴影线中的每个点应满

当然 这个条件在产生随机数时就已经保证了,
故可以不再考虑了。
因此,要同时满足公式 1和公式 2,雨点才能落入阴影线
区域,语句
22 11xy ? ? ? ?公式
22( 1 ) 1xy? ? ? ? ?公式2
0,1xy??
21
if ((sqrt(x*x+y*y)>1)&&(sqrt((x-1)*(x-1)+y*y)>1))
g=g+1;
就是依据上述的思路。
为了比较所得结果是否有效,程序中给出了 s 的精确值,
这个值是用几何的解法计算出的,见图
无阴影线部分可分解为 ABA三块
3
1 2 4 1 2
1 - ( )
A
B
A B A
s A B A
??
? ? ? ? ?
? ? ?
,圆面积
,边长为1 的等边三角形
A A
B
30 °
30 °
22
参考程序如下(随机函数 6.c)
#include <stdio.h> // 预编译命令
#include <math.h> // 预编译命令
#include <stdlib.h> // 预编译命令
void main(void) // 主函数
{ // 主函数开始
long k,d=0,g=0; // 定义长整型变量
float s,x,y; // 定义浮点类型变量
srand( (unsigned)time(NULL)); // 设置
23
for(k=1;k<=10000000;k=k+1) // 循环
{ // 循环体开始
d=d+1; // 累加正方形中落入的一个雨点
x=(float)rand()/32767; // 雨点在 x方向的位置
y=(float)rand()/32767; // 雨点在 y方向的位置
if((sqrt(x*x+y*y)>1)&&(sqrt((x-1)*(x-1)+y*y)>1))
g=g+1;// 累加阴影面积中落入的一个雨点
} // 循环体结束
s=(float)g/d; // 计算 s的值
printf("s= %f\n",s); // 输出 s的值
// 输出 s的精确值
printf("s的精确值为 %f\n",1.0-(3.14159/6.0+1.73205/4.0));
}
24
整数分拆
题目:有一个整数 n,将 n分解成若干个整数之和,问如
何分解能使这些数的乘积最大,输出这个乘积 m。
分析:分解出的数既不是越多越好,也不是越大越好。

( 1)分解为 1+1+1+…+1, 12个 1
( 2)分解为 2+2+…+2, 6个 2
12n ?
1 1 1 1 1m ? ? ? ? ?
62 6 4m ??
25
( 3)分解为 3+3+3+3,4个 3
( 4)分解为 4+4+4,3个 4
( 5)分解为 6+6,2个 6
( 6)分解为 5+7
( 7)分解为 4+8
43 8 1m ??
34 6 4m ??
26 3 6m ??
5 7 3 5m ? ? ?
4 8 3 2m ? ? ?
26
显然,3最好。
算法:见与或结点图。
n
k=n/ 3;
m= p(k) ;
k=(n- 2)/ 3;
m= 2*p(k) ;
n%3== 2n%3== 0
n%3== 1
k=(n- 4)/ 3;
m= 4*p(k) ;
27
图的说明,
1,当 n可以被 3整除时,就让 n分解成 k个 3,。
之后,调用一个算 3的 k次方的函数 p(k),输出 p(k)。
2,当 n除 3余 1时,可分解为 1,3,3,…,3 。 从使乘积最大
的角度出发,我们不希望分解出 1来,这时,宁可让 1
与其中的一个 3合并,为 4。让,接着
调用 p(k),但输出时再将原来减去的 4当作一个乘数
乘进来,即输出 4*p(k)。
3,当 n除 3余 2时,可分解为 2,3,3,…,3 。可以沿用上诉
思路让,求 p(k)。 最后输出时将 2乘
入,即输出 2*p(k)。
4,这个程序我们采用多分支选择语句,格式为
3kn?
( 4 ) 3kn??
( 2 ) 3kn??
28
switch(表达式 )
{
case 常量表达式 1,{ 语句块 1; }
case 常量表达式 2,{ 语句块 2; }
case 常量表达式 n,{ 语句块 n; }
}
switch后面括弧中的表达式的值与 case后面的常量
表达式的值相等时,就执行其后的语句。比如
29
switch( a )
{
case 0, { b = 1; break; }
case 1, { b = 10; break; }
case 2, { b = 100; break; }
case 3, { b = 1000; break; }
case 4, { b = 10000; }
}
实践上完成的任务是
30
注意,
不可以没有 break。 如果没有的话,不管 a为 0,还
是为 1,为 2或为 3,b的值均为 10000。
1,0
10,1
100,2
100 0,3
100 00,4
a
a
ba
a
a
??
?
?
?
?
???
?
?
?
??
?
31
参考程序如下( n的分解,c)
#include <stdio.h> //预编译命令
long p(int ) ; //声明函数 p为长整型,
//形参为整型
void main() //主函数
{ //主程序开始
int n,k; //整型变量
long m; //长整型
printf("请输入正整数 n=" ); //提示信息
scanf("%d",&n); //输入正整数 n
switch(n % 3) //多分支选择语句
{//switch
32
case 0:{ //n % 3 为 0 时做
k=n/3;
m=p(k); //p(k)为被调用函数
break;
}
case 1:{ //n % 3 为 1 时做
k=(n-4)/3;
m=4*p(k); //p(k)为被调用函数
break;
}
case 2:{ //n % 3 为 2 时做
k=(n-2)/3;
m=2*p(k); //p(k)为被调用函数
break;
}
}//switch
33
printf("最大乘积为 %ld\n",m); //输出结果
} //主程序结束
//以下函数是被主程序调用的函数
long p(int kk) //长整型自定义函数
//形参 kk为整型变量
{ //自定义函数体开始
int i,mm=1; //整型变量
for(i=1;i<=kk;i=i+1) //累乘 3,放入中
mm=mm*3;
return mm; //返回 mm值
} //自定义函数体结束