Add Fast Powering algorithm.

This commit is contained in:
Oleksii Trekhleb 2018-09-04 18:27:38 +03:00
parent 8116aa7cfb
commit 7dc60c96bf
2 changed files with 79 additions and 43 deletions

View File

@ -1,39 +1,68 @@
# Fast Powering Algorithm # Fast Powering Algorithm
This computes power of (a,b) **The power of a number** says how many times to use the number in a
eg: power(2,3) = 8 multiplication.
power(10,0) = 1
The algorithm uses divide and conquer approach to compute power. It is written as a small number to the right and above the base number.
Currently the algorithm work for two positive integers X and Y
Lets say there are two numbers X and Y.
At each step of the algorithm:
1. if Y is even
then power(X, Y/2) * power(X, Y/2) is computed
2. if Y is odd
then X * power(X, Y/2) * power(X, Y/2) is computed
At each step since power(X,Y/2) is called twice, this is optimised by saving the result of power(X, Y/2) in a variable (lets say res). ![Power](https://www.mathsisfun.com/algebra/images/exponent-8-2.svg)
And then res is multiplied by self.
Illustration through example ## Naive Algorithm Complexity
power (2,5)
- 2 * power(2,2) * power(2,2)
power(2,2)
- power(2,1) * power(2,1)
power(2,1)
- return 2
Going up the tree once the end values are computed How to find `a` raised to the power `b`?
power(2,1) = 2
power(2,2) = power(2,1) * power(2,1) = 2 * 2 = 4
power(2,5) = 2 * power(2,2) * power(2,2) = 2 * 4 * 4 = 32
We multiply `a` to itself, `b` times. That
is, `a^b = a * a * a * ... * a` (`b` occurrences of `a`).
Complexity relation: T(n) = T(n/2) + 1 This operation will take `O(n)` time since we need to do multiplication operation
exactly `n` times.
Time complexity of the algorithm: O(logn) ## Fast Power Algorithm
Can we do better than naive algorithm does? Yes we may solve the task of
powering in `O(log(n))` time.
The algorithm uses divide and conquer approach to compute power. Currently the
algorithm work for two positive integers `X` and `Y`.
The idea behind the algorithm is based on the fact that:
For **even** `Y`:
```text
X^Y = X^(Y/2) * X^(Y/2)
```
For **odd** `Y`:
```text
X^Y = X^(Y//2) * X^(Y//2) * X
where Y//2 is result of division of Y by 2 without reminder.
```
**For example**
```text
2^4 = (2 * 2) * (2 * 2) = (2^2) * (2^2)
```
```text
2^5 = (2 * 2) * (2 * 2) * 2 = (2^2) * (2^2) * (2)
```
Now, since on each step we need to compute the same `X^(Y/2)` power twice we may optimise
it by saving it to some intermediate variable to avoid its duplicate calculation.
**Time Complexity**
Since each iteration we split the power by half then we will call function
recursively `log(n)` times. This the time complexity of the algorithm is reduced to:
```text
O(log(n))
```
## References ## References
- [YouTube](https://www.youtube.com/watch?v=LUWavfN9zEo&index=80&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
- [Wikipedia](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)

View File

@ -1,23 +1,30 @@
/** /**
* Fast Powering Algorithm.
* Recursive implementation to compute power. * Recursive implementation to compute power.
* *
* @param {number} number1 * Complexity: log(n)
* @param {number} number2 *
* @param {number} base - Number that will be raised to the power.
* @param {number} power - The power that number will be raised to.
* @return {number} * @return {number}
*/ */
export default function fastPowering(number1, number2) { export default function fastPowering(base, power) {
let val = 0; if (power === 0) {
let res = 0; // Anything that is raised to the power of zero is 1.
if (number2 === 0) { // if number2 is 0 return 1;
val = 1;
} else if (number2 === 1) { // if number2 is 1 return number 1 as it is
val = number1;
} else if (number2 % 2 === 0) { // if number2 is even
res = fastPowering(number1, number2 / 2);
val = res * res;
} else { // if number2 is odd
res = fastPowering(number1, Math.floor(number2 / 2));
val = res * res * number1;
} }
return val;
if (power % 2 === 0) {
// If the power is even...
// we may recursively redefine the result via twice smaller powers:
// x^8 = x^4 * x^4.
const multiplier = fastPowering(base, power / 2);
return multiplier * multiplier;
}
// If the power is odd...
// we may recursively redefine the result via twice smaller powers:
// x^9 = x^4 * x^4 * x.
const multiplier = fastPowering(base, Math.floor(power / 2));
return multiplier * multiplier * base;
} }