求大数阶乘前要计算下最大数阶乘的位数

以便于知道需要开多大的数组 .

第一种求法 : 
lg(N!)=[lg(N*(N-1)*(N-2)*......*3*2*1)]+1


          =[lgN+lg(N-1)+lg(N-2)+......+lg3+lg2+lg1]+1

+1是为了向上取整,因为结果可能是小数


#include<cstdio>
#include<cmath>
int main()
{
double sum=0;
for(int i=1;i<=10000;i++) // n是10000的情况下
sum+=log10(i);
printf("%d\n",(int)sum+1);
return 0;
}


第二种求法:运用斯特林公式来计算 n! 的位数

斯特林公式(Stirling's approximation)是一条用来取n的​阶乘​​的​​近似值​​的数学公式。一般来说,当n很大的时候,n阶乘的计算量十分大,所以斯特林公式十分好用,而且,即使在n很小的时候,斯特林公式的取值已经十分准确。

大数阶乘_大数阶乘


用Stirling公式计算n!结果的位数时,可以两边取对数,
得: log10(n!) = log10(2*PI*n)/2+n*log10(n/E); 
故n!的位数= log10(2*PI*n)/2+n*log10(n/E)+1(注意:当n=1时,算得的结果为0)

#include<cstdio>
#include<cmath>
#define PI 3.141592654
#define E 2.71828182846
int main()
{
int n,sum=1;
scanf("%d",&n);
if(n>3)
sum=log10(2*PI*n)/2+n*log10(n/E)+1;
printf("%d\n",sum);
return 0;
}

求大数阶乘运用的是模拟,也是用一个数组来储存这个阶乘的每一位数


练习题目:​​http://acm.hdu.edu.cn/showproblem.php?pid=1042​


#include<cstdio>
#include<cmath>
#include<cstring>
int a[35660+5];//储存每一位所得得数
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(a,0,sizeof(a));
int temp,dight=1;
a[0]=1;
dight=1;//dight是阶乘的位数
for(int i=1;i<=n;i++)
{
int num=0;//保存需要进位的数
for(int j=0;j<dight;j++)
{
temp=a[j]*i+num;//temp是每次相乘的结果
a[j]=temp%10;
num=temp/10;//保存需要进位的数
}
while(num)
{
a[dight]=num%10;//继续储存
num/=10;
dight++;
}
}
for(int i=dight-1;i>=0;i--)//逆序输出每一位
printf("%d",a[i]);
printf("\n");
}
return 0;
}

上边的那一段代码在51nod里​​https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1057​​这一道题会TLE

我提交了好多次,才在有一次以 1000ms 通过....


看了别人写的代码,有的100ms内就通过了,简直是我速度的十倍


他们的代码不是让a[i]只保存一位数,而是保存多位,见过一位大佬的,一个a[i]保存了14位数,我也写了一下,140ms过了这道题

#include<cstdio>  
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const ll c=1e14;
ll a[10000000];
int main()
{
ll n;
while(~scanf("%lld",&n))
{
ll temp;
ll dight=1;
a[0]=1;
for(ll i=1;i<=n;i++)
{
ll num=0;
for(ll j=0;j<dight;j++)
{
temp=a[j]*i+num;
a[j]=temp%c;
num=temp/c;
}
if(num!=0)
{
a[dight++]=num;
}
}
printf("%lld",a[dight-1]);
for(ll i=dight-2;i>=0;i--)
printf("%014lld",a[i]);//这样也可以
// printf("%0.14lld",a[i]);//这里想不明白为什么要加个.
printf("\n");
}
return 0;
}
//这个代码可以计算1e4以内的数,超过这个范围的话数据会溢出,需要在修改一下a[i]的最大储存位数
//就这段代码而言,a[i]最多储存1e14大小的数,要是在乘个1e5的数,结果是1e19大小,肯定会溢出
//所以测试99999!的时候前边出现了负号。。。



em.....


Python大法好...一次通过

n=eval(input())
sum=int(1)
for i in range(1,n+1):
sum=sum*i
print(sum)


当然还有更强的,直接引用函数,78ms过的

import math
n = int(input())
print(math.factorial(n))



看了众多大佬的代码,受益匪浅。共勉之


参考:https://baike.baidu.com/item/%E6%96%AF%E7%89%B9%E6%9E%97%E5%85%AC%E5%BC%8F/9583086