mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-27 15:41:16 +08:00
Add Fast Powering algorithm.
This commit is contained in:
parent
8116aa7cfb
commit
7dc60c96bf
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user