繁体   English   中英

如何在C ++中找到以1000000007为模的大阶乘分解?

[英]How do I find factorials of large numbers modulo 1000000007 in C++?

查找大数的阶乘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;
 }

但是输出无效。

检查此代码。 没问题,因为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 < INT_MAX条件,因为如果我们不使用它,则如果n = INT_MAX,则for循环的索引增量(i ++)可能会导致INT_MAX的值增加,这将使其变为0。因此,该条件永远不会为false,并且它将陷入无限循环。

注意 :如果要精确计算c ++中的阶乘,则可以采用1000个字符的数组,其中每个字符代表一个数字。 然后您将逐渐繁殖以获得结果。 N *(N-1)* .. 2 * 1

注意 :如果要进行许多递归调用,则可能会导致堆栈内存溢出,因为每个函数调用都会导致推入一个帧(包含它的返回点等)。

如果x!! = 1 * 3 * 5 * 7 * 9 * 11 * ... ,然后是2x! = 2x!! * 2^x * x! 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!!结果x!! ,因为这些重复频率很高。

缓存实时示例 ,通过缓存x!! ,大约是大型n 实例的 2倍x!! 合理地估价。 每次对double_factorial(n)调用都会创建lg k个缓存条目,其中k是n与最大的旧缓存条目之间的距离。 由于k以n为界。 实际上,这似乎在第一次调用后将加权的“缓存未命中”减少到几乎为零: n!!的第一次计算n!! 注入足够的缓存条目,以使我们在以后的!!计算中不会花费大量时间!!

这个优化的版本比单纯的迭代实现快41%(基本上所有时间都花在计算第一个n!! )。

进一步的改进可能涉及制作第一个x!! 计算速度更快,而优化缓存可能会带来一些改进。 下一个问题:你怎么做x!! 快点?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM