我们来一步一步说明白级数的计算问题。
一、输入整数n,计算 s,其中 s=1+2+3+...+n
这是一个累加问题,把从1到n累加到s上。
#include<stdio.h>
int main(void)
{
int n,sum=0,i;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
sum=sum+i;
}
printf("%d",sum);
return 0;
}
二、输入整数n,计算f,其中:f= n!
这是一个累乘问题。
#include<stdio.h>
int main(void)
{
int n,f=1,i;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
f=f*i;
}
printf("%d",f);
return 0;
}
三、计算s=1!+2!+3!+...+n!
这是一个累加与累乘的混合。
一共是n项,对于第 x 项需要计算 x!,然后累加到总和sum上面。
#include<stdio.h>
int main(void)
{
int n,sum=0,x,i,f;
scanf("%d",&n);
for(x=1;x<=n;x++)
{//x代表第x项
//下面的循环用来计算 f=x!
f=1;
for(i=1;i<=x;i++)
{
f=f*i;
}
sum=sum+f;
}
printf("%d",sum);
return 0;
}
仔细分析一下这 n 项,第 x 项是第 x-1 项的 x 倍,有这样的一个关系,
这样就可以利用上一次计算的x-1项的结果。
#include<stdio.h>
int main(void)
{
int n,sum=0,x,i,f_x_1,f_x;
scanf("%d",&n);
f_x_1=1;//f_x_1初值是1,假设是第0项,第1项是第0项的1倍
for(x=1;x<=n;x++)
{
f_x=f_x_1*x;//第x项是第x-1项的x倍
sum=sum+f_x;
f_x_1=f_x;//在下一轮 ,该计算x+1项了,f_x是新的前一项了
}
printf("%d",sum);
return 0;
}
等熟悉了,就可以省略掉一个变量,变为:
#include<stdio.h>
int main(void)
{
int n,sum=0,x,i,f,f_x;
scanf("%d",&n);
f_x=1;//fx初值是1,假设是第0项,第1项是第0项的1倍
for(x=1;x<=n;x++)
{
f_x=f_x*x;//第x项是第x-1项的x倍
sum=sum+f_x;
}
printf("%d",sum);
return 0;
}
四、更复杂的级数
输入一个n和一个x,n是整数,代表后面一共有n项,x是实数,代表角度,单位是弧度,计算:
比如 角度为30度的角对应的弧度为 30*pi/180
这个计算比较复杂,有阶乘、有幂,有符号的交替
1、先看最笨的方法。找通项公式。
#include<stdio.h>
#include "math.h"
int main(void)
{
int n,y,i;
double f,x,item,sum=0;
scanf("%d %lf",&n,&x);//输入时x是度数
x=x*3.1415926/180;
f=1;//f初值是1,假设是第0项,第1项是第0项的1倍
for(i=1;i<=n;i++)
{
item=pow(-1,i+1)*pow(x,2*i-1);
//下面计算(2*i-1)!
f=1;
for(y=1;y<=2*i-1;y++)
f=f*y;
item=item/f;
sum=sum+item;
}
printf("%f",sum);
return 0;
}
显然,能解决问题,容易理解;
但是双重循环,复杂,且有阶乘的计算,幂的计算,计算量大。
我们可以把求阶乘的功能用函数包装起来,使得形式简单。
2、函数法
#include<stdio.h>
#include "math.h"
int fact(int n)
{
int f=1,i;
for(i=2;i<=n;i++)
f=f*i;
return f;
}
int main(void)
{
int n,y,i;
double x,item,sum=0;
scanf("%d %lf",&n,&x);//输入时x是度数
x=x*3.1415926/180; //度数转换为弧度
for(i=1;i<=n;i++)
{
item=pow(-1,i+1)*pow(x,2*i-1)/fact(2*i-1); //第i项的值
sum=sum+item;
}
printf("%f",sum);
return 0;
}
可以看到,引入了求阶乘的函数,main函数的主体就清晰明了很多。
但计算的时间效率却没有改观。
应该考虑前后项之间的关系。
3、前后项法
令第i项是f_i,其x的指数是 2*i-1;
第i-1项是f_i_1, 其x的指数是 2*i-3
有下面的关系
f_i=f_i_1*(-1)*x*x/(2*i-2)/(2*i-1);
#include<stdio.h>
int main(void)
{
int n,i;
double f_i,f_i_1,x,sum=0;
scanf("%d %lf",&n,&x);//输入时x是度数,n是第几项
x=x*3.1415926/180;
f_i_1=x;//f初值是x,假设是第1项
sum=x;
if(n==1)
{
printf("%f\n",sum);
return 0;
}
for(i=2;i<=n;i++)
{
f_i=f_i_1*(-1)*x*x/(2*i-2)/(2*i-1);
sum=sum+f_i;
f_i_1=f_i;
}
printf("%f",sum);
return 0;
}
4、不走寻常路
前后项法是非常好的一种方法。
但若题目改成这样:
题目描述:根据下面求sin(x)的级数公式,计算sin(x)的值。其中x是弧度。
比如 角度为30度的角对应的弧度为 30*pi/180
输入:
输入有多行,每一行有两个数,n和x,n代表整数(1<=n<=20),n代表角度,单位是度数。
输出:
对应输入的每一行,输出对应的sin(x),每行输入对应一行输出。
这样这个题目就变成ACM竞赛形式的题目了。
按照前后项的技巧,也需要每行计算n!。
我们可以先计算出所有的n!,记录在数组中。
#include<stdio.h>
#include "math.h"
int main(void)
{
int n,y,i;
int fact[21] ={1,1};
for(i=2;i<=20;i++)
fact[i]=fact[i-1]*i;
while(1)
{
double x,item,sum=0;
int ret=scanf("%d %lf",&n,&x);//输入时x是度数
if(ret!=2)//如果读入的不是两个数,说明没数据了
break;
x=x*3.1415926/180; //度数转换为弧度
double item2=x;//第一项的符号和幂部分之积
sum=x; //第一项
if(n==1)
{
printf("%f\n",sum);
continue;
}
for(i=2;i<=n;i++)
{
item2=item2*(-1)*x*x;
item=item2/fact[2*i-1]; //第i项的值
sum=sum+item;
}
printf("%f\n",sum);
}
return 0;
}
把一些固定不变的值事先计算并记录下来,是一种常用的方法。俗称“查表法”。