c语言-大数阶乘
大数阶乘的由来
一个正整数的阶乘(Factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。亦即n!=1×2×3×…×(n-1)×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。 但是在求解数字较大的阶乘时,由于阶乘累乘的性质,导致结果过大,在C语言中,哪怕是double和Longlong都无法储存过多的数位,而解决这个问题的办法,最简单的就是由数组来储存。
大致思路
由于是超过了一个定义变量的最大范围,所以使用数组解决,毕竟C语言中 int的范围为-(2的31次方-1)到(2的31次方-1),数字为-2 147 483 647~2 147 483 647。double的表示范围为+1.111111111111111111111*2^1023(1.后面52个1)为1.7*10^308,看起来double型应该够了的,可是,精度却并不高,数值精度只有 15~16 位,就是说,一个 308 位长的浮点数,只有前 15~16 位的精度是可信和有保证的,超出部分就没有精度可言了,而且,越靠后,就越不靠谱。而数组申请一个过万的空间轻轻松松,每个空间再存int或double型数据,加在一起可以输出的空间就可想而知了。
用数组解决该问题,简单来说就是就是将大数的各个位置用取余取出放在数组的连续空间上,然后逆序输出。而其中需要注意的就是化繁为简,分解成多个子问题进行计算(是不是有些耳熟),即在已经分布好位置的n-1的数位上进行下一次的阶乘,保证了每位相乘都是一个很小的数字去乘下一个阶乘数。运用双循环分别进行乘数的移动和每位数字与此时乘数的计算,最后输出。下面是代码:
1 #define N 10001 2 int a[N]; 3 double arr[N]; 4 5 void factorial1(int n) 6 { 7 a[0] = 1; 8 int len = 1; 9 int tmp, next; 10 for (int i = 1; i <= n; i++) 11 { 12 next = 0; 13 for (int j = 0; j < len; j++) 14 { 15 tmp = a[j] * i+next; //当前阶乘值 16 a[j] = tmp % 10; //当前位置仅保留阶乘值的最后一位 17 next = tmp / 10; //保存大于10的余下阶乘值,进行下一次存储 18 if (j >= len - 1 && next > 0) //动态增加数组长度 19 { 20 len++; //当数组在最后一位且存在next值时,就增加一个长度进行下一次存储。 21 } 22 } 23 } 24 for (int i = len-1; i >=0 ; i--)//倒叙输出数组 25 { 26 printf("%d",a[i]); 27 if (i % 5 == 0&&i!=0)//分组输出,每组5个 28 printf(","); 29 } 30 }