找出大数模数1000000007的阶乘
在Python或Java中,没有问题,但在C ++中存在溢出约束。
这是我尝试过的代码:
#include<iostream>
#define ull long long int
#define mod 1000000007
ull fact(ull n)
{
if(n==1 || n==0) return 1;
return ((n%mod)*(fact(n-1)%mod)%mod);
}
int main()
{
cout<<fact(50000)<<endl;
return 0;
}
但输出无效。
答案 0 :(得分:1)
检查此代码。应该没有任何问题,因为unsigned long long可以轻松存储任何模块化值10 ^ 9 + 7。我的意思是如果你使用的是模块化值而不是实际值,那你为什么要关心呢? (众所周知,10 ^ 9 + 7可以存储在ull中)。
ull ans;
ull fact(int n)
{
if(n<INT_MAX)
{
ans=1;
for(int i=2;i<=n;i++)
ans=(ans*i)%mod;
return ans;
}
}
这只是做阶乘。
这里n&lt;使用INT_MAX
条件是因为如果我们不使用它,那么如果n = INT_MAX,for循环的索引增量(i ++)可能会导致INT_MAX的值增加,这将使它成为0.因此条件永远不会为假它会遇到无限循环。
注意:如果要精确计算c ++中的阶乘,可以使用1000个字符数组,其中每个字符代表一个数字。然后你会逐渐乘以得到结果。 N *(N-1)* .. 2 * 1
注意:如果你正在进行许多递归调用,那么它可能会导致堆栈内存溢出,因为每个函数调用都会导致推送一个帧(包含它的返回点等)。
答案 1 :(得分:0)
如果x!!
= 1 * 3 * 5 * 7 * 9 * 11 * ...
,则2x!
= 2x!! * 2^x * x!
。
这为我们提供了更有效的因子算法。
template<ull mod>
struct fast_fact {
ull m( ull a, ull b ) const {
ull r = (a*b)%mod;
return r;
}
template<class...Ts>
ull m( ull a, ull b, Ts...ts ) const {
return m( m( a, b ), ts... );
}
// calculates x!!, ie 1*3*5*7*...
ull double_fact( ull x ) const {
ull ret = 1;
for (ull i = 3; i < x; i+=2) {
ret = m(i,ret);
}
return ret;
}
// calculate 2^2^n for n=0...bits in ull
// a pointer to this is stored statically to make calculating
// 2^k faster:
ull const* get_pows() const {
static ull retval[ sizeof(ull)*8 ] = {2%mod};
for (int i = 1; i < sizeof(ull)*8; ++i) {
retval[i] = m(retval[i-1],retval[i-1]);
}
return retval;
}
// calculate 2^x. We decompose x into bits
// and multiply together the 2^2^i for each bit i
// that is set in x:
ull pow_2( ull x ) const {
static ull const* pows = get_pows();
ull retval = 1;
for (int i = 0; x; ++i, (x=x/2)){
if (x&1) retval = m(retval, pows[i]);
}
return retval;
}
// the actual calculation:
ull operator()( ull x ) const {
x = x%mod;
if (x==0) return 1;
ull result = 1;
// odd case:
if (x&1) result = m( (*this)(x-1), x );
else result = m( double_fact(x), pow_2(x/2), (*this)(x/2) );
return result;
}
};
template<ull mod>
ull factorial_mod( ull x ) {
return fast_fact<mod>()(x);
}
更快的版本可以重复使用x!!
的结果,因为这些结果经常重复。
Caching live example,通过合理智能地缓存x!!
值,对于大n的速度大约是上述速度的2倍。每次调用double_factorial(n)
都会创建lg k个缓存条目,其中k是n与最大旧缓存条目之间的距离。因为k受n的限制。这在实践中似乎减少了加权&#34;缓存未命中&#34;在第一次调用后几乎为零:n!!
的第一次计算注入了足够的缓存条目,我们在以后的!!
计算中不会消耗大量时间。
这个优化版本比天真的迭代实现快了大约41%(基本上所有的时间都花在计算第一个n!!
上)。
进一步改进可能涉及使第一次x!!
计算更快,优化缓存可能略有改进。下一个问题:如何让x!!
更快?