昨天闲来无事我写了两个计算大数字阶乘和乘方的程序。写这个东西主要原因是因为我的第一次面试。今年春天我去北京一家很不错的公司面试,其中有一项是笔试,命题人出了一道这样的题:试计算2^256,写出编程思想,不要求最后结果。作为一名还未走出校门的学生,其实应变这样的一道题应该说也不算太难,思路很简单,就是用一个数组存储结果,其中每个数项治村结果的几位,然后按照像《计算机组成原理》中介绍的乘法器那样进行逻辑实现。我当时就是这么很简单的写了一个实现思路,当时面试的9个人中,做对这道题的人只有我一个,因此我就凭这道题为自己争得了一个很高的印象分,虽然后来由于某些原因我没有去那家公司,但是这也算是我的一次面试成功经历,所以还是记忆犹新。下面是我在UNIX下编写的计算阶乘的程序,其实现思路和乘方运算差不多。具体流程注释中应该很清楚了。
#include <stdio.h>
/****************
此函数fact()实现计算大数字阶乘
参数 n int型
返回结果整形数为0则表示出错,否则打印结果
*****************/
int fact(int n)
{
int a[900];/*记录结果*/
int flag=1;/*结果位数标志*/
int data=n;/*计算过程中的被乘数*/
int i = 0;/*循环标志*/
/*只对0———1041之间的数进行计算*/
if((n < 0)||(n > 1042))
{
printf("数字溢出!\n");
return 0;
}
/*0的阶乘单独处理*/
if(n == 0)
{
printf("0 !=1\n ");
return 0;
}
/*如果输入的值大于2位,初始化头两个数组值*/
if(n >= 1000)
{
flag = 2;
}
a[0] = 1;
/*主运算*/
while((data > 0)&&(flag < 900))
{
/*将上次的结果和下一个被乘数进行一轮运算*/
for(i=0; i<flag; i++)
{
a[i] = a[i] * data;
}
/*调整结果*/
for(i=0; i<flag-1; i++)
{
a[i+1] += a[i]/1000;
a[i] = a[i] % 1000;
}
/*调整结果*/
if(a[flag-1] > 1000)
{
flag++;
a[i+2] = a[i+1] / 1000;
a[i+1] = a[i+1] % 1000;
}
/*被乘数自减*/
data--;
}
/*结果的打印*/
printf("%d != ",n);
printf("%d",a[flag-1]);
/*针对三位数字的头两位是否为0进行处理*/
for(i=flag-2; i>=0; i--)
{
if(a[i]<100)
printf("0");
if(a[i]<10)
printf("0");
printf("%d",a[i]);
}
printf("\n");
return 1;
}
main()
{
fact(1000);
}
执行结果:
1000 != 40238726007709377354370243392300398571937486421071463254379991042
99385123986290205920442084869694048004799886101971960586316668729
94808558901323829669944590997424504087073759918823627727188732519
77950595099527612087497546249704360
……(限于篇幅,这里就不再罗列太多的数字)00000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000
这样一段计算大数字阶乘的代码就完成了,很简单吧!但是说到简单,我还见到不知出自何处的这样一段代码,风格好坏暂且不管,即使有人称之为是一小堆垃圾代码,但是它能计算pi到小数点后面1000位之多,你说厉害么?
#include <stdlib.h>
#include <stdio.h>
main()
{
long a=10000,b,c=2800,d,e,f[2801],g;
for(;b-c;)
f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)
for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);
}
打印结果:
31415926535897932384626433832795028841971693993751058209749445923
07816406286208998628034825342117067982148086513282306647093844609
55058223172535940812848111745028410270193852110555964462294895493
03819644288109756659334461284756482337867831652712019091456485669
23460348610454326648213393607260249141273724587006606315588174881
52092096282925409171536436789259036001133053054882046652138414695
19415116094330572703657595919530921861173819326117931051185480744
62379962749567351885752724891227938183011949129833673362440656643
08602139494639522473719070217986094370277053921717629317675238467
48184676694051320005681271452635608277857713427577896091736371787
21468440901224953430146549585371050792279689258923542019956112129
02196086403441815981362977477130996051870721134999999837297804995
10597317328160963185
当然如果数学基础比较好的同学可以利用一些有关级数的公式,很容易写出计算pi小数点后上万位的代码,可能也不会超过几十行,但是要想精简到此种程度也着实不易。
上面介绍的只不过是大数字运算的一点皮毛,真正涉及到理论的东西远不止这么肤浅,除非你是专门研究这个的或者有很新的创意,否则根本用不着费那么大的力气去自己编写一些进行大数字运算的函数,如果只是为了应用,你可以选择象Maple那样的数学软件,它的大数字运算足以满足你的需求,它可以一下打印出10000!,数字可以滚好几屏!