首先,在本篇文章开头提供我看到的挺好的阶乘解法(c描述)的链接:https://blog.csdn.net/lisp1995/article/details/52403507
我的解法也是参考他的思路的.
众所周知,普通的阶乘100以内(或者更小),我们是可以直接算的(简单的迭代或者递归),但当超过一定的long long int(64位)范围,就会溢出,这时我们就不能直接通过定义变量来求了,这时所求的数我们就该叫做大数了,一说到大数,我们就不是从变量的角度出发了,而是从数组的角度出发,采用最原始的人工计算方法,而且数组元素是用来做位数的,每一个元素做一位,从而能够存储更大范围的数。
注意一下,在这里我们首先要知道要求的范围内最大的数的阶乘的位数,以便为数组申请空间,我百度了一下:https://baike.baidu.com/item/%E9%98%B6%E4%B9%98/4437932?fr=aladdin
公式在应用那里:n! = 10^M ->lg n! = M -> lg1+lg2+lg3+lg4+…+lgn = M
直接循环求值就可以知道位数了,我求得1000!的位数是2567.6也就是2568位
emmm,好了,开始解释阶乘求法
我们首先申请一定的数组空间,
我们令a[0] 等于1作为初始值,dig作为位数 ,为1,temp 是临时值,用来存放某个位上的数的乘积
比如
因为a[0] = 1
刚开始的时候 设进位的数 num为0
temp = a[0]*2 +num=2
a[0] = temp%10 = 2
num =temp/10=0 显然是符合的 因为乘以2的时候是没有进位
接下来是a[0]*3 类似上面
接下来是a[0]*4
此时 temp = a[0]*4+num = 24 也就是 个位是 4 十位 是2
所以
a[0] = temp%10 = 4 a[1] 来存 2 也就是 num=temp/10
刚刚我们在设置位数的时候只是一位 所以 num还保存着向前进的数 ,所以在外面加个循环用于将上一次求得最后的num(num>0)向前进位保存
(该方法是模拟竖式乘法
0 6
x 4
——
2 4
你可以通过用笔计算来模拟。)
接下来是a[0]*5 ,a[1]*5+num
也就是 24x5 相当于 4x5 = 20 向前进2 本位是0 代码操作temp = a[0]{4} x 5+num(每次新乘一个数的时候 num都会初始化为0) 所以 temp = 20
那么a[0] = temp%10 = 0 刚好符合了本位的数是0 num = temp/ 10=2
刚好符合向前进的数是 2
然后就是2x5 = 10 加上之前4x5进的数 2 就是12 所以temp = 12
所以保存在本位 的是 2(12%10) 向前进一位 是 1
所以用a[2]存上一位的进的数 1
所以此时逆过来输出(a[2]a[1]a[0] )是不是 120
…后面的计算都是类似这样的
参考代码
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int a[2600];
int temp,dig,n,num;//temp 是一个临时的值,用来存放的是每一位计算的结果 dig 是位数
//num是上一位所向前进的数
cin >> n;
a[0] = 1;//初始化个位的数为 1
dig = 1; //位数是 1(刚开始的时候)
for(int i = 2;i <= n;++i )
{
num = 0; //刚开始的时候 num的值是 0
//以位数来循环求值 dig是位数 刚开始的时候是1
for(int j = 0;j < dig;++j)
{
/*temp 用来存放某个位上的乘积(模拟竖式乘法单独位数相乘)加上 上一位位数 求得所向下一位数(数学中称满10进1)进的数*/
temp = a[j]*i+num;
a[j] = temp%10; //记得满10进1的原则 也就是对10求余的数才是本位保留的数 是10的倍数的是要进位
num = temp /10; //进位
}
// 检查num是否是大于0 如果大于0 则说明还得向前进位
while(num)
{
a[dig] = num%10;
num/=10;
++dig;
}
}
//高位是在后面的 逆回来读
for(int i = dig -1;i >= 0;--i)
{
printf("%d",a[i]);
}
return 0;
}