经验技巧6-2 大数阶乘优化算法

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

经验技巧6-2 大数阶乘优化算法

【例6-6】给出了大数阶乘的算法,该算法使用数组存放阶乘的结果,每一个数组元素存放结果的一位。计算十万的阶乘需要近260秒的时间,实际上只要程序中的N足够大,还可以求更大数的阶乘,但程序执行的时间会更长,可能要几个小时,甚至更长,因此需要考虑对算法进行优化。

int型数组的每一个元素可以存放的最大整数为2147483647,是一个十位数,而算法中每一个元素只存放结果的一位,显然太浪费了。

由于算法中需要计算自然数n与数组元素值的乘积加上前一位的进位,所以每个数组元素的位数不能太多,否则将超过最大整数2147483647而导致溢出,如果每个数组元素存放4位数,大约可计算到二十万的阶乘,确保结果是精确的,如果再使用无符号基本整型,大约可计算到四十万的阶乘,确保结果是精确的。

由此,定义符号常量M的值为10000作为模数,符号常量B的值为4表示数组元素存放的最多位数,符号常量N的值为600000表示n!结果位数的B分之一,存放n!结果的数组bit定义为静态无符号基本整型。

计算i!时将原来的用10除处理进位和余数改为用M除。

由于除存放最高位的元素外,每个元素都存放B位,而存放最高位的元素可能不足B位,输出前需先统计存放最高位元素bit[k]的位数,另外,低位的0(只能输出一个0)和不足B位的应使用B个输出域宽,不足的用0补足,才能保证其它各位均输出B位。

其它说明详见程序代码中的注释。

优化的程序代码:

(1)#include "stdio.h"

(2)#define M 10000//M与n的乘积不能超过4294967295

(3)#define B 4//数组元素存放的最多位数

(4)#define N 600000 //n!的位数,要足够大

(5)int fact(int bit[],int n)

(6){

(7)int i,j,k=N-1,carry;//k表示第一个非0元素的下标

(8)bit[k]=1;

(9)for(i=2;i<=n;i++)

(10){

(11)carry=0;//carry表示进位数,开始进位数为0

(12)for(j=N-1;j>=k;j--)

(13){

(14)bit[j]=bit[j]*i+carry; (15)carry=bit[j]/M;//处理进位(16)bit[j]=bit[j]%M;

(17)

if(j==k&&carry)//当处理到(i-1)!的最高位元素时(即j==k),只要有进位(即carry!=0),最高位元素下标前移

(18)k--;

(19)}

(20)}

(21)return k;

(22)}

(23)int main()

(24){

(25)static unsigned bit[N]={0}; //存放n!的结果

(26)int i,j=0,k,n;

(27)printf("请输入一个不超过四十万的自然数,计算它的阶乘:"); (28)scanf("%d",&n);

(29)k=fact(bit,n);

(30)for(i=bit[k];i;i=i/10)//统计存放最高位元素的位数

(31)j++;

(32)printf("%d!=%d",n,bit[k]);//输出最高位元素的值

(33)for(i=k+1;i

(34)

printf("%0*d",B,bit[i]);//输出其它各位元素的值,位数均为B,低位0均输出B个0

(35)printf("\n");

(36)printf("%d!是一个%d位数\n",n,j+(N-k-1)*B);

(37)return 0;

(38)}

优化后的程序计算十万的阶乘只需65秒,计算四十万的阶乘需要不到19分钟。

相关文档
最新文档