【问题标题】:What is the fastest way to compute large power of 2 modulo a number计算2模数的大幂的最快方法是什么
【发布时间】:2012-07-02 07:39:08
【问题描述】:

对于1 &lt;= <i>N</i> &lt;= 1000000000,我需要计算2<sup><i>N</i></sup> mod 1000000007,而且速度一定非常快!
我目前的做法是:

ull power_of_2_mod(ull n) {
    ull result = 1;
    if (n <= 63) {
        result <<= n;
        result = result % 1000000007;
    }
    else {
        ull one = 1;
        one <<= 63;
        while (n > 63) {
            result = ((result % 1000000007) * (one % 1000000007)) % 1000000007;
            n -= 63;
        }

        for (int i = 1; i <= n; ++i) {
            result = (result * 2) % 1000000007;
        }

    }

    return result;
}

但它似乎不够快。有什么想法吗?

【问题讨论】:

标签: c++ c algorithm optimization numbers


【解决方案1】:

这样会更快(C 代码):

typedef unsigned long long uint64;

uint64 PowMod(uint64 x, uint64 e, uint64 mod)
{
  uint64 res;

  if (e == 0)
  {
    res = 1;
  }
  else if (e == 1)
  {
    res = x;
  }
  else
  {
    res = PowMod(x, e / 2, mod);
    res = res * res % mod;
    if (e % 2)
      res = res * x % mod;
  }

  return res;
}

【讨论】:

  • 不错。但是有可能(尽管不一定)摆脱递归。可以计算 2 的不同幂次方的残差,即 2^1、2^2、2^4、2^8 等。此计算以直序迭代完成。然后对实际功率进行比特测试,揭示所需的“成分”
  • 不应该是res = x % mode == 1 分支吗?
  • @Christoph If x &gt;= mod,绝对是。
  • 问题:res * res 很容易溢出。建议 uint32 PowMod(uint32 x, uint32 e, uint324 mod) 并使用 64 位数学执行 *。 2:次要 PowMod(0, e&gt;0, ...) 应返回 0。PowMod(..., 0, 1) 应返回 0。
【解决方案2】:

此方法不使用 O(log(n)) 复杂度的递归。看看这个。

#define ull unsigned long long
#define MODULO 1000000007

ull PowMod(ull n)
{
    ull ret = 1;
    ull a = 2;
    while (n > 0) {
        if (n & 1) ret = ret * a % MODULO;
        a = a * a % MODULO;
        n >>= 1;
    }
    return ret;
}

这是来自Wikipedia 的伪代码(参见从右到左的二进制方法部分)

function modular_pow(base, exponent, modulus)
Assert :: (modulus - 1) * (base mod modulus) does not overflow base
result := 1
base := base mod modulus
while exponent > 0
    if (exponent mod 2 == 1):
       result := (result * base) mod modulus
    exponent := exponent >> 1
    base := (base * base) mod modulus
return result

【讨论】:

  • @chux a*a
  • 是的 - 对于 OP 的“1 a*a < N*N 没问题。仅适用于 pow(2,32) 或更大的 ull 值。
【解决方案3】:

你可以在O(log n)解决。

例如,对于 n = 1234 = 10011010010(以 2 为底),我们有 n = 2 + 16 + 64 + 128 + 1024,因此 2^n = 2^2 * 2^16 * 2^64 * 2 ^128 * 2 ^ 1024。

请注意,2^1024 = (2^512)^2,因此,如果您知道 2^512,则可以通过几个操作计算 2^1024。

解决方案是这样的(伪代码):

const ulong MODULO = 1000000007;

ulong mul(ulong a, ulong b) {
    return (a * b) % MODULO;
}

ulong add(ulong a, ulong b) {
    return (a + b) % MODULO;
}

int[] decompose(ulong number) {
    //for 1234 it should return [1, 4, 6, 7, 10]
}

//for x it returns 2^(2^x) mod MODULO
// (e.g. for x = 10 it returns 2^1024 mod MODULO)
ulong power_of_power_of_2_mod(int power) {
    ulong result = 1;
    for (int i = 0; i < power; i++) {
        result = mul(result, result);
    }
    return result;
}

//for x it returns 2^x mod MODULO
ulong power_of_2_mod(int power) {
    ulong result = 1;
    foreach (int metapower in decompose(power)) {
        result = mul(result, power_of_power_of_2_mod(metapower));
    }
    return result;
}

请注意,O(log n) 实际上是 O(1) 用于 ulong 参数(如 log n uint MODULO (MODULO

【讨论】:

    【解决方案4】:

    可以在 O((log n)^2) 内求解。 试试这个方法:-

    unsigned long long int fastspcexp(unsigned long long int n)
    {
        if(n==0)
            return 1;
        if(n%2==0)
            return (((fastspcexp(n/2))*(fastspcexp(n/2)))%1000000007);
        else
            return ( ( ((fastspcexp(n/2)) * (fastspcexp(n/2)) * 2) %1000000007 ) ); 
    }
    

    这是一种递归方法,速度非常快,足以满足大多数编程比赛的时间要求。

    【讨论】:

    • O(log(n)^2) 方法。您确定不应该手动消除公共子表达式吗?
    【解决方案5】:

    如果您还想存储该数组,即。 (2^i)%mod [i=0 to whatever] 比:

    long mod = 1000000007;
    long int pow_mod[ele]; //here 'ele' = maximum power upto which you want to store 2^i
    pow_mod[0]=1; //2^0 = 1
    for(int i=1;i<ele;++i){
        pow_mod[i] = (pow_mod[i-1]*2)%mod;
    }
    

    我希望它对某人有所帮助。

    【讨论】:

      猜你喜欢
      • 2014-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-03
      • 1970-01-01
      • 2017-06-27
      • 2012-07-27
      • 1970-01-01
      相关资源
      最近更新 更多