大数阶乘
为了考虑精度问题,所以大数阶乘需要一个算法
首先来看,100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
所以一个 64位的 long long 型,数据存不下,所以需要考虑新的思路,利用数组来存储位数。
考虑,一个位数上为 6 ,乘上8 ,得到进位十位为 4,个位为 8,就让8存储在当前位,4就存储在下一位(数组中的数是从前往后存储的)。
在考虑一下,数组可以开的大小在 105-106左右,所以能存储的最大位为 106,所以在考虑一下,能不能让数组中的每个数的位数都用。就可以每一位存储10的4次方,像1111*2222 = 2468642,进位数为246,余数为8642,2222再乘上8642 又有进位数和余数实现数的存储。
这样利用数的存储空间int型4位可以用109 或者 long long 型8位可以用1018,就会大于使用char型数组1字节1位,就会最大的利用空间。
注意:单独输出 a[num] 表示的意思是最后一次计算后得到的值 t 没有取模,所以可能会大于maxn的数。
大致就是这个过程,可以参考代码:
#include<stdio.h>
#include<math.h>
int maxn_s(int n){
int cnt = 0;
while(n){
n /= 10;
cnt++;
}
return cnt;
}
int factorial(int n){ //返回值为数的位的个数
const int maxn = 10000; //表示数组中一个数存最大的位数
const int s = maxn_s(maxn)-1; //表示maxn的位数函数
printf("数组a中每一位存储的数据范围为%d个9",s);
int a[maxn] = {1}; //数组初始化,除了a[0] = 1外,其他的数默认赋值为0
int t,num = 0;
for(int i = 1;i <= n;i++) //表示1-n每一个都乘一遍
{
t = 0; //t表示进位的数
for(int j = 0;j <= num;j++){
a[j] = a[j]*i + t;
t = a[j]/maxn; //表示进的位
a[j] = a[j]%maxn; //表示除了进位的剩下来的数
}
if(t > 0) {num++;a[num] = t;} //如果每一次乘法后,最大的一位是否会超过边界,超过就会让数组第一位存下超过的数
}
int length = num*s + log10(a[num]) + 1;
printf("\n%ld",a[num]);
for(int i = num-1;i >= 0;i--) printf("%4.4d",a[i]); //详细看最下面解释
return length;
}
int main()
{
int n; //n的阶乘
scanf("%d",&n);
int s = factorial(n);
printf("\n字符的长度%d",s);
return 0;
}
解释一下:lenght 表示这个数的长度,s表示数组中每一个数存几位,num * s + log10(a[num]) + 1 中,num*s 表示除一个数最前面num位上的数,剩下的位数,而log10(a[num]) 表示最后一位数可能会很大,所以就要用 log10(a[num]) 来表示(例 log10111 强制类型转化后得到的只是 2,但是 111有3位,所以最后面又加了一个 1)所以具体就是这样。
%4.4d中,
4的意思表示留4位的空间
.4表示保留4位数
1)超4位的数删掉(这里不用这一条)。
2)小于4位就补 0。