Search code examples
c++mathmodular-arithmetic

Why don't we need to perform modulo operation on every operands in Fast Power algorithm?


Today I practiced with a puzzle "fast power", which used a formula: (a * b) % p = (a % p * b % p) % p to calculate (a^n)%p, something like that: 2^31 % 3 = 2

However, I am so confused when I found the answer used ((temp * temp) % b * a) % b; to solved situation when n is odd, like 2^3

(temp is (temp * temp) % b * a recursively or (temp * temp) % b).

Should not it be ((temp * temp) % b * a%b) % b?

Since according to this formula, everything should %b before times together.


Solution

  • Should not it be ((temp * temp) % b * a % b) % b?

    No. For a, if you know beforehand that a won't overflow(a is smaller than b), you don't have to mod it.

    The idea is modular arithmetic works for addition and multiplication. Operation like (a + b) % M = (a % M + b % M) % M and (a * b) % M = (a % M * b % M) % M are generally performed to avoid overflow of (a * b) and (a + b) and keep the value under certain range.

    Example:

    const int Mod = 7;
    int a = 13;
    int b = 12;
    int b = b % Mod; // b now contains 5 which is certainly smaller than Mod
    
    int x = (a % Mod * b) % Mod; // you won't need to mod b again if you know beforehand b is smaller than Mod
    

    Update

    C++ implementation of power function:

    #define MOD 1000000007
    // assuming x and n both be positive and initially smaller than Mod
    int power(int x, int n) {
        if(n == 0) return x;
        int half = power(x, n / 2) % Mod;
        int ret = (half * half) % Mod; // you didn't need to do (half % Mod * half % Mod) % Mod because you already know half is smaller than Mod and won't overflow. 
                                       // Modulas being performed on the multiplied output, so now ret will be smaller than Mod
        if(n & 1) {
            ret = (ret * x) % Mod; // you didn't need to do (ret % Mod * x % Mod) % Mod
                                   // because you already know ret and x is smaller than Mod
        }
        return ret;
    }
    

    Mod is an expensive operation. So you should avoid it whenever possible.