Fast Exponentiation

autor: iamtwz, billchenchina, CBW2007, CCXXXI, chinggg, Enter-tainer, eyedeng, FFjet, gaojude, Great-designer, H-J-Granger, Henry-ZHR, hsfzLZH1, Ir1d, kenlig, Konano, ksyx, luoguyuntianming, Marcythm, Menci, NachtgeistW, ouuan, Peanut-Tang, qwqAutomaton, sshwy, StudyingFather, Tiphereth-A, TrisolarisHD, TRSWNCA, Xeonacid, Yuuko10032, Zhangjiacheng2006, Zhoier, Hszzzx, shenshuaijie, kfy666

Introduction

Fast exponentiation (fast exponentiation), also called binary exponentiation (binary exponentiation) or exponentiation by squaring (exponentiation by squaring), is a small technique for computing ana^n in Θ(log⁡n)\Theta(\log n) time, whereas brute-force computation requires Θ(n)\Theta(n) time.

This technique can be applied whenever multiplication involving aa is associative, such as modular exponentiation and matrix powers. See the later Applications section for details.

Process

Computing the nn-th power of aa means multiplying nn copies of aa together: an=a×a⋯×a⏟n 个 aa^{n} = \underbrace{a \times a \cdots \times a}_{n\text{ 个 a}}. However, this method is not suitable when nn is too large or a single multiplication is too expensive. The idea of binary exponentiation is to divide the exponentiation task into smaller tasks according to the exponent's binary representation.

Example

Suppose we want to compute 3133^{13}. Expanding it as a product requires 13−1=1213-1=12 multiplications. However,

313=3(1101)2=38×34×31,3^{13} = 3^{(1101)_2} = 3^8 \times 3^4 \times 3^1,

so if we can quickly compute 31,32,34,383^{1},3^{2},3^{4},3^{8}, we can compute 3133^{13} with 22 multiplications. Thus, we only need a fast way to compute the sequence for 33 with exponents 2k2^k. This is easy because, except for the first element, every element in the sequence is the square of the previous element.

From this analysis, the computation of 3133^{13} is as follows:

31=3,32=(31)2=32=9,34=(32)2=92=81,38=(34)2=812=6561,313=6561×81×3=1594323.\begin{aligned} 3^1 &= 3, \\ 3^2 &= \left(3^1\right)^2 = 3^2 = 9, \\ 3^4 &= \left(3^2\right)^2 = 9^2 = 81, \\ 3^8 &= \left(3^4\right)^2 = 81^2 = 6561, \\ 3^{13} &= 6561 \times 81 \times 3 = 1594323. \end{aligned}

Only 55 multiplications are performed in this process.

This is the basic idea of fast exponentiation. There are two common implementations.

Iterative version

Let the binary representation of nn be (ntnt−1⋯n1n0)2(n_tn_{t-1}\cdots n_1n_0)_2, that is,

n=nt2t+nt−12t−1+⋯+n121+n020,n = n_t2^t + n_{t-1}2^{t-1} + \cdots + n_12^1 + n_02^0,

where ni∈{0,1}n_i\in\{0,1\}. Then,

an=ant2t+nt−12t−1+⋯+n121+n020=an020×an121×⋯×ant−12t−1×ant2t.\begin{aligned} a^n & = a^{n_t2^t + n_{t-1}2^{t-1} + \cdots + n_12^1 + n_02^0}\\ & = a^{n_0 2^0} \times a^{n_1 2^1}\times \cdots \times a^{n_{t-1}2^{t-1}} \times a^{n_t2^t}. \end{aligned}

Note that only terms with ni=1n_i=1 actually appear in the product.

According to this expression, we can first compute the Θ(log⁡n)\Theta(\log n) values of the 2k2^k-th powers of aa in Θ(log⁡n)\Theta(\log n) time, and then spend Θ(log⁡n)\Theta(\log n) time multiplying into the final result the powers corresponding to binary bits equal to 11. This is the iterative implementation of fast exponentiation.

The pseudocode is as follows:

Algorithm FastPow(a,n):Input. Base a and exponent n.Output. Power an.Method.1result←Id2while n>0 do3if n mod 2=1 then4result←result⋅a5end if6a←a⋅a7n←n/28end while9return result\begin{array}{l} \textbf{Algorithm }\text{FastPow}(a, n): \\ \textbf{Input. }\text{Base }a\text{ and exponent }n.\\ \textbf{Output. }\text{Power }a^n.\\ \textbf{Method.}\\ \begin{array}{ll} 1 & \textit{result}\gets\mathrm{Id}\\ 2 & \textbf{while }n > 0\textbf{ do}\\ 3 & \qquad \textbf{if }n \bmod 2 = 1\textbf{ then}\\ 4 & \qquad \qquad \textit{result} \gets \textit{result}\cdot a\\ 5 & \qquad \textbf{end if}\\ 6 & \qquad a \gets a \cdot a\\ 7 & \qquad n \gets n / 2\\ 8 & \textbf{end while}\\ 9 & \textbf{return }\textit{result} \end{array} \end{array}

Computing fast exponentiation this way requires Θ(log⁡n)\Theta(\log n) multiplications.

Recursive version

The same process can also be implemented recursively. Notice that the binary expansion of the exponent nn can be written recursively as

(ntnt−1⋯n1n0)2=2×(ntnt−1⋯n1)2+n0.(n_tn_{t-1}\cdots n_1n_0)_2 = 2 \times (n_tn_{t-1}\cdots n_1)_2 + n_0.

Therefore, ana^n can be computed recursively as

an={1,n=0,(a⌊n/2⌋)2,n>0 and n is even,(a⌊n/2⌋)2⋅a,n>0 and n is odd.a^n = \begin{cases} 1, & n = 0,\\ (a^{\lfloor n/2\rfloor})^2, & n > 0 \text{ and }n\text{ is even},\\ (a^{\lfloor n/2\rfloor})^2\cdot a, & n > 0 \text{ and }n\text{ is odd}.\\ \end{cases}

This is the recursive implementation of fast exponentiation.

The pseudocode is as follows:

Algorithm FastPow(a,n):Input. Base a and exponent n.Output. Power an.Method.1if n=0 then2return Id3end if4result←FastPow(a,n/2)5if n mod 2=0 then6return result⋅result7else8return result⋅result⋅a9end if\begin{array}{l} \textbf{Algorithm }\text{FastPow}(a, n): \\ \textbf{Input. }\text{Base }a\text{ and exponent }n.\\ \textbf{Output. }\text{Power }a^n.\\ \textbf{Method.}\\ \begin{array}{ll} 1 & \textbf{if }n = 0\textbf{ then}\\ 2 & \qquad \textbf{return }\mathrm{Id}\\ 3 & \textbf{end if}\\ 4 & \textit{result} \gets \text{FastPow}(a, n / 2) \\ 5 & \textbf{if }n\bmod 2 = 0\textbf{ then}\\ 6 & \qquad \textbf{return }\textit{result}\cdot\textit{result}\\ 7 & \textbf{else}\\ 8 & \qquad \textbf{return }\textit{result}\cdot\textit{result}\cdot a\\ 9 & \textbf{end if} \end{array} \end{array}

Computing fast exponentiation this way requires Θ(log⁡n)\Theta(\log n) recursive calls and also Θ(log⁡n)\Theta(\log n) multiplications. Although the complexities are the same, the iterative version is faster in practice because recursion has some overhead.

Applications

Modular exponentiation

Luogu P1226 [Template] Fast Exponentiation

Given three integers a,b,pa,b,p, find ab mod pa^b\bmod p, where p≥2p\ge 2.

This is a very common application; for example, it can be used to compute a modular multiplicative inverse. Since taking a modulus does not interfere with multiplication, we only need to take the modulus during the computation.

First, we can implement it directly according to the recursive method above:

Reference implementation

C++

long long binpow(long long a, long long b, long long p) {
  if (b == 0) return 1;
  long long res = binpow(a, b / 2, p);
  if (b % 2)
    return res * res % p * a % p;
  else
    return res * res % p;
}

Python

def binpow(a, b, p):
    if b == 0:
        return 1
    res = binpow(a, b // 2, p)
    if (b % 2) == 1:
        return res * res * a % p
    else:
        return res * res % p

The second implementation is non-recursive. It multiplies into the answer the powers corresponding to binary bits equal to 1 during the loop. Although the theoretical complexities of the two are the same, the second is faster in practice because recursion incurs some overhead.

Reference implementation

C++

long long binpow(long long a, long long b, long long p) {
  long long res = 1;
  while (b > 0) {
    if (b & 1) res = res * a % p;
    a = a * a % p;
    b >>= 1;
  }
  return res;
}

Python

def binpow(a, b, p):
    res = 1
    while b > 0:
        if b & 1:
            res = res * a % p
        a = a * a % p
        b >>= 1
    return res
Note
  • The modulus is usually greater than 11. In the very special case where the modulus pp may equal 11, the case b=0b=0 needs special consideration.
  • When the exponent is very large, use Euler's theorem extension to reduce the exponent before computing.

Computing Fibonacci numbers

According to the recurrence Fn=Fn−1+Fn−2F_n = F_{n-1} + F_{n-2} of the Fibonacci sequence, we can construct a 2×22\times 2 matrix to represent the transformation from Fi,Fi+1F_i,F_{i+1} to Fi+1,Fi+2F_{i+1},F_{i+2}. Then, when computing the nn-th power of this matrix, we can use the idea of fast exponentiation to obtain the result in Θ(log⁡n)\Theta(\log n) time. For more details, see Fibonacci sequence; an implementation of matrix fast exponentiation is available in Matrix-accelerated recurrence.

Multiple permutations

Problem statement

Given a sequence of length nn and a permutation, apply the permutation kk times to the sequence.

Simply raise the permutation to the kk-th power and apply it to the sequence. The time complexity is O(nlog⁡k)O(n \log k). For more details, see Composition of permutations.

Note

Construct a graph for the permutation and compute the kk-th power separately on each cycle (which is equivalent to taking kk modulo the cycle length); this solves the problem in O(n)O(n) time.

Accelerating operations on point sets in geometry

HDU 4087 A Letter to Programmers

Given nn points pip_i in three-dimensional space, apply mm operations to these points. There are 3 types of operations:

  1. Move a point along a vector (Shift).
  2. Scale the coordinates of the point proportionally (Scale).
  3. Rotate around a line (Rotate).

There is also a special operation: repeat an operation sequence kk times (Repeat). Repeat operations can be nested. Output the coordinates of every point after all operations.

Referring to Vectors and matrices, each operation can be represented by a transformation matrix, and a sequence of consecutive transformations can be represented by a product of matrices. A Repeat operation is equivalent to raising a matrix to the kk-th power. Thus, the final matrix of the entire transformation sequence can be computed in O(mlog⁡k)O(m \log k) time. Applying it to the nn points gives total complexity O(n+mlog⁡k)O(n + m \log k).

Counting paths of fixed length

Problem statement

Given a directed graph with edge weights 1, find, for any two vertices u,vu,v, the number of paths of length kk from uu to vv.

Raise the adjacency matrix MM of the graph to the kk-th power. Then Mi,jM_{i,j} is the number of paths of length kk from ii to jj. The complexity is O(n3log⁡k)O(n^3 \log k). See the Matrix page for details.

Modular integer multiplication

Problem statement

Given nonnegative integers a,ba,b and a positive integer mm, compute a×b mod ma\times b\bmod m, where a,b≤m≤1018a,b\le m\le 10^{18}.

As with binary exponentiation, this time we express one of the factors as a sum of integer powers of 2. When multiplying a number by 2 and taking a modulus, we can use addition and subtraction to avoid integer overflow. This solves the problem in O(log⁡m)O (\log m) time. The recursive method is:

a⋅b={0if a=02⋅a2⋅bif a>0 and a even2⋅a−12⋅b+bif a>0 and a odda \cdot b = \begin{cases} 0 &\text{if }a = 0 \\ 2 \cdot \frac{a}{2} \cdot b &\text{if }a > 0 \text{ and }a \text{ even} \\ 2 \cdot \frac{a-1}{2} \cdot b + b &\text{if }a > 0 \text{ and }a \text{ odd} \end{cases}

In practice, however, this method is inefficient because it introduces greater computational complexity. In actual programming, fast multiplication is usually used for multiplication when the modulus range is long long.

High-precision fast exponentiation

Prerequisite: Big-integer multiplication

Luogu P1045 [NOIP 2003 Primary Group] Mersenne Number

Given an integer PP (1000<P<31000001000 < P < 3100000), find the number of digits of 2P−12^P−1 and its last 500500 digits (written in decimal). If there are fewer than 500500 digits, pad the higher positions with 0.

Implementation
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;

const int M = 500;

int a[505], b[505], t[505];

// big-integer multiplication
void mult(int x[], int y[]) {
  memset(t, 0, sizeof(t));
  for (int i = 1; i <= x[0]; i++) {
    for (int j = 1; j <= y[0]; j++) {
      if (i + j - 1 > M) continue;
      t[i + j - 1] += x[i] * y[j];
      t[i + j] += t[i + j - 1] / 10;
      t[i + j - 1] %= 10;
      t[0] = i + j;
    }
  }
  memcpy(b, t, sizeof(b));
}

// fast exponentiation
void binpow(int p) {
  if (p == 1) {
    memcpy(b, a, sizeof(b));
    return;
  }
  binpow(p / 2);  // (2^(p/2))^2=2^p
  mult(b, b);     // square b
  if (p % 2 == 1) mult(b, a);
}

int main() {
  cin.tie(nullptr)->sync_with_stdio(false);
  int p;
  cin >> p;
  a[0] = 1;  // record the number of digits in array a
  a[1] = 2;  // square 2
  b[0] = 1;  // record the number of digits in array b
  b[1] = 1;  // answer array
  binpow(p);
  cout << (int)(log10(2) * p) + 1 << '\n';
  b[1] -= 1;  // subtract 1 from the last digit
  for (int i = M; i >= 1; i--) {
    cout << b[i];
    if ((i - 1) % 50 == 0) {
      cout << '\n';
    }
  }
}

Precomputed fast exponentiation with a fixed base

When the base aa is fixed, we can use block decomposition to preprocess for some amount of time and answer each power query in O(1)O(1) time. This algorithm is also called light-speed exponentiation. The process is as follows:

  1. Select a number ss. Precompute the values of a0,a1,⋯ ,as−1a^0,a^1,\cdots,a^{s-1} and a0,as,⋯ ,a⌊p/s⌋sa^0,a^s,\cdots,a^{\lfloor p/s\rfloor s} and store them in two arrays.
  2. For each query aba^b, decompose bb as ⌊b/s⌋s+(b mod s)\lfloor b/s\rfloor s+(b\bmod s). Then ab=a⌊b/s⌋s⋅ab mod sa^b=a^{\lfloor b/s\rfloor s}\cdot a^{b\bmod s}, so the answer can be obtained in O(1)O(1) time.

Suppose the range of the exponent bb is [0,n][0,n]. The block length ss is often chosen as n\sqrt{n} or a nearby power of 22. Choosing n\sqrt{n} gives the optimal preprocessing complexity O(n)O(\sqrt{n}), while choosing a power of 22 allows bit operations to simplify the computation.

In particular, for modular exponentiation, having the same base aa also implies that the modulus mm must be the same. By Euler's theorem extension, for any modulus mm, the upper bound of the preprocessed exponent range is n=2φ(m)n = 2\varphi(m); for a prime modulus pp, the upper bound is n=p−1n = p - 1. The preprocessing complexity in both cases is O(m)O(\sqrt{m}).

Reference code
int a, mod, pow1[65536], pow2[65536];

void preproc() {
  pow1[0] = pow2[0] = 1;
  for (int i = 1; i < 65536; i++) pow1[i] = 1LL * pow1[i - 1] * a % mod;
  int pow65536 = 1LL * pow1[65535] * a % mod;
  for (int i = 1; i < 65536; i++) pow2[i] = 1LL * pow2[i - 1] * pow65536 % mod;
}

int query(int pows) {
  return 1LL * pow1[pows & 65535] * pow2[pows >> 16] % mod;
}

Exercises

Some content on this page is translated from the blog post Binary Exponentiation and its English translation Binary Exponentiation. The Russian version is licensed under Public Domain + Leave a Link; the English version is licensed under CC-BY-SA 4.0.

This content comes from OI Wiki: Fast Exponentiation. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.