TheAlgorithms-C-Plus-Plus/math/fast_power.cpp
Bahadir Altun 79d50738f2 Add fast power (#691)
* Add fast power

Computes a^b in O(logN) time.

* Change long long to int64_t

* Update fast_power.cpp

* Update fast_power.cpp

* Add tests

* Update sample tests

* Update rand function

* Remove extra-spaces
2019-12-26 09:30:30 +01:00

80 lines
2.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <cstdlib>
#include <cstdint>
#include <cassert>
#include <ctime>
#include <cmath>
/*
Program that computes a^b in O(logN) time.
It is based on formula that:
case1) if b is even: a^b = a^(b/2) * a^(b/2) = (a^(b/2))ˆ2
case2) if b is odd: a^b = a^((b-1)/2) * a^((b-1)/2) * a = (a^((b-1)/2))^2 * a
We can compute a^b recursively using above algorithm.
*/
double fast_power_recursive(int64_t a, int64_t b) {
// negative power. a^b = 1 / (a^-b)
if (b < 0)
return 1.0 / fast_power_recursive(a, -b);
if (b == 0) return 1;
int64_t bottom = fast_power_recursive(a, b >> 1);
// Since it is integer division b/2 = (b-1)/2 where b is odd.
// Therefore, case2 is easily solved by integer division.
int64_t result;
if ((b & 1) == 0) // case1
result = bottom * bottom;
else // case2
result = bottom * bottom * a;
return result;
}
/*
Same algorithm with little different formula.
It still calculates in O(logN)
*/
double fast_power_linear(int64_t a, int64_t b) {
// negative power. a^b = 1 / (a^-b)
if (b < 0)
return 1.0 / fast_power_linear(a, -b);
double result = 1;
while (b) {
if (b & 1) result = result * a;
a = a * a;
b = b >> 1;
}
return result;
}
int main() {
std::srand(time(NULL));
std::ios_base::sync_with_stdio(false);
std::cout << "Testing..." << std::endl;
for (int i = 0; i < 20; i++) {
unsigned int *rand1, *rand2;
int a = rand_r(rand1) % 20 - 10;
int b = rand_r(rand2) % 20 - 10;
std::cout << std::endl << "Calculating " << a << "^" << b << std::endl;
assert(fast_power_recursive(a, b) == std::pow(a, b));
assert(fast_power_linear(a, b) == std::pow(a, b));
std::cout << "------ " << a << "^" << b << " = "<<
fast_power_recursive(a, b) << std::endl;
}
int64_t a, b;
std::cin >> a >> b;
std::cout << a << "^" << b << " = "<<
fast_power_recursive(a, b) << std::endl;
std::cout << a << "^" << b << " = "<<
fast_power_linear(a, b) << std::endl;
return 0;
}