Exponencial Rápida

El algoritmo de exponencial rápida tiene como objetivo reducir la complejidad del cálculo de $$a^b$$, para:


 * $$b \in \mathbb{N}$$
 * $$a \in \mathbf{M}$$
 * $$(\mathbf{M}, *)$$ forma un monóide.

Este algoritmo sirve para números reales, números complejos y matrices.

Método convencional
El método convencional, hacemos un loop y en cada iteracion, multiplicamos nuestro resultado parcial por a. Por exemplo: int potencia(int a, int b) { s = 1; for (int i = 0; i < b; i++) {       s *= a;    } return s; }

Para este método, el loop será ejecutado $$b \,$$ veces, y la complejidad es $$O(n) \,$$

Método de exponencial rápida
En este método, vamos ha escrebir un número b en base-2 (binário).


 * $$b = \sum_{i}{k_i 2^i}, k \in {0, 1}$$

Substituiendo, tenemos:



\begin{tabular}{ll} $a^b$ & = $a^{\sum_{i}{k_i 2^i}}$ \\ & = $\prod_{i}{a^{k_i 2^i}}$ \\ & = $\prod_{i}{(a^{2^i})}^{k_i}$ \end{tabular} $$

Notemos una recurrencia bastante simple: $$a^{2^{(i+1)}} = {(a^{2^i})}^2$$. int potencia(int a, int b) { s = 1; for (b != 0; b >>= 1, a *= a)   { if (b&1) {           s *= a;        } }   return s; }

El loop del código de arriba será ejecutado $$\lceil log_{2}{b} \rceil + 1$$ veces.

Por tanto, la complejidad del código es $$O( \log{n} ) \,$$

Método recursivo de la exponencial rápida
Utilizando la idea de Divide y vencerás. Este algoritmo consiste en un método recursivo que calcula $$a^b$$ del siguiente modo:

$$ \mbox{power}(a,\,b)= \begin{cases} 1, & \mbox{si }b\mbox{ = 0} \\ a\times \left(\mbox{power}(a,\,\frac{b-1}{2})\right)^2, & \mbox{si }b\mbox{ es impar} \\ \left(\mbox{power}(a,\,\frac{b}{2})\right)^2, & \mbox{si }b\mbox{ es par} \end{cases} $$

De esa forma, el código recursivo para la exponenciacion rápida seria de la siguinte forma: int power(int a, int b) { if(b == 0) return 1; if(b & 1) { // es decir, si b es impar: int k = power(a, (b - 1) / 2); return a * k * k;   } else {       int k = power(a, b / 2); return k * k;   } }

Este algoritmo tambien posee complejidad $$O( \log{n} ) \,$$. Entre tanto, para números muy grandes se debe escojer el método iterativo, visto que su consumo de memoria es bien reducida comparado con el recursivo.