经验技巧6-2 大数阶乘优化算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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分钟。