9

For 1 <= N <= 1000000000, I need to compute 2N mod 1000000007, and it must be really fast!
My current approach is:

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;
}

but it doesn't seem to be fast enough. Any idea?

Eitan T
  • 32,660
  • 14
  • 72
  • 109
roxrook
  • 13,511
  • 40
  • 107
  • 156
  • Looks really good IMHO. Perhaps I'd remove the first `if`, i.e. always go to the general case. – valdo Jul 02 '12 at 07:45
  • 1
    this is math problem... 1000000007 is prime and you should take a look here: http://www.math.sunysb.edu/~scott/blair/Powers_modulo_prime.html – astreal Jul 02 '12 at 07:46
  • @astreal: Thanks a lot. I should be aware of `prime`, Shame! – roxrook Jul 02 '12 at 07:47
  • possible duplicate of [how to calculate 2^n modulo 1000000007 , n = 10^9](http://stackoverflow.com/questions/23846699/how-to-calculate-2n-modulo-1000000007-n-109) – phuclv May 12 '15 at 05:53
  • Check [exponentiation by squaring](http://en.wikipedia.org/wiki/Exponentiation_by_squaring) and binary method of [modular exponentiation](http://en.wikipedia.org/wiki/Modular_exponentiation) – MBo Jul 02 '12 at 07:46

5 Answers5

8

This will be faster (code in 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;
}
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • Nice. But it's possible (though not necessarily) to get rid of the recursion. It's possible to calculate resid for different powers of power of 2, i.e. 2^1, 2^2, 2^4, 2^8 and etc. This calculation is done iteratively in straight order. Then bittesting the actual power reveals the needed "ingredients" – valdo Jul 02 '12 at 07:56
  • shouldn't that be `res = x % mod` in the `e == 1` branch? – Christoph Jul 02 '12 at 08:17
  • @Christoph If `x >= mod`, absolutely. – Alexey Frunze Jul 02 '12 at 08:25
  • Problems: `res * res` can readily overflow. Suggest `uint32 PowMod(uint32 x, uint32 e, uint324 mod)` and do `*` with 64-bit math. 2: Minor `PowMod(0, e>0, ...)` should return 0. `PowMod(..., 0, 1)` should return 0. – chux - Reinstate Monica Oct 24 '15 at 04:02
6

This method doesn't use recursion with O(log(n)) complexity. Check this out.

#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;
}

And this is pseudo from Wikipedia (see Right-to-left binary method section)

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
Paul Lo
  • 6,032
  • 6
  • 31
  • 36
5

You can solve it in O(log n).

For example, for n = 1234 = 10011010010 (in base 2) we have n = 2 + 16 + 64 + 128 + 1024, and thus 2^n = 2^2 * 2^16 * 2^64 * 2^128 * 2 ^ 1024.

Note that 2^1024 = (2^512)^2, so that, given you know 2^512, you can compute 2^1024 in a couple of operations.

The solution would be something like this (pseudocode):

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;
}

Note that O(log n) is, in practice, O(1) for ulong arguments (as log n < 63); and that this code is compatible with any uint MODULO (MODULO < 2^32), independent of whether MODULO is prime or not.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
penartur
  • 9,792
  • 5
  • 39
  • 50
1

It can be solved in O((log n)^2). Try this approach:-

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 ) ); 
}

This is a recursive approach and is pretty fast enough to meet the time requirements in most of the programming competitions.

nikoo28
  • 2,961
  • 1
  • 29
  • 39
0

If u also want to store that array ie. (2^i)%mod [i=0 to whatever] than:

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;
}

I hope it'll be helpful to someone.

Polish
  • 554
  • 1
  • 4
  • 18