2020-05-26 21:05:44 +08:00
|
|
|
/**
|
|
|
|
* @file
|
2020-05-28 03:14:39 +08:00
|
|
|
* @brief Faster computation for \f$a^b\f$
|
|
|
|
*
|
|
|
|
* Program that computes \f$a^b\f$ in \f$O(logN)\f$ time.
|
|
|
|
* It is based on formula that:
|
|
|
|
* 1. if \f$b\f$ is even:
|
|
|
|
* \f$a^b = a^\frac{b}{2} \cdot a^\frac{b}{2} = {a^\frac{b}{2}}^2\f$
|
|
|
|
* 2. if \f$b\f$ is odd: \f$a^b = a^\frac{b-1}{2}
|
|
|
|
* \cdot a^\frac{b-1}{2} \cdot a = {a^\frac{b-1}{2}}^2 \cdot a\f$
|
|
|
|
*
|
|
|
|
* We can compute \f$a^b\f$ recursively using above algorithm.
|
|
|
|
*/
|
2019-12-26 16:30:30 +08:00
|
|
|
|
2020-05-26 21:05:44 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <ctime>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* algorithm implementation for \f$a^b\f$
|
|
|
|
*/
|
2020-05-28 03:14:30 +08:00
|
|
|
template <typename T>
|
2020-05-30 07:26:30 +08:00
|
|
|
double fast_power_recursive(T a, T b)
|
|
|
|
{
|
2019-12-26 16:30:30 +08:00
|
|
|
// negative power. a^b = 1 / (a^-b)
|
2020-05-30 07:26:30 +08:00
|
|
|
if (b < 0)
|
|
|
|
return 1.0 / fast_power_recursive(a, -b);
|
2019-12-26 16:30:30 +08:00
|
|
|
|
2020-05-30 07:26:30 +08:00
|
|
|
if (b == 0)
|
|
|
|
return 1;
|
2020-05-28 03:14:30 +08:00
|
|
|
T bottom = fast_power_recursive(a, b >> 1);
|
2019-12-26 16:30:30 +08:00
|
|
|
// Since it is integer division b/2 = (b-1)/2 where b is odd.
|
|
|
|
// Therefore, case2 is easily solved by integer division.
|
|
|
|
|
2020-05-28 03:14:30 +08:00
|
|
|
double result;
|
2019-12-26 16:30:30 +08:00
|
|
|
if ((b & 1) == 0) // case1
|
|
|
|
result = bottom * bottom;
|
|
|
|
else // case2
|
|
|
|
result = bottom * bottom * a;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-05-26 21:05:44 +08:00
|
|
|
/**
|
2019-12-26 16:30:30 +08:00
|
|
|
Same algorithm with little different formula.
|
2020-05-28 03:14:39 +08:00
|
|
|
It still calculates in \f$O(\log N)\f$
|
2019-12-26 16:30:30 +08:00
|
|
|
*/
|
2020-05-28 03:14:30 +08:00
|
|
|
template <typename T>
|
2020-05-30 07:26:30 +08:00
|
|
|
double fast_power_linear(T a, T b)
|
|
|
|
{
|
2019-12-26 16:30:30 +08:00
|
|
|
// negative power. a^b = 1 / (a^-b)
|
2020-05-30 07:26:30 +08:00
|
|
|
if (b < 0)
|
|
|
|
return 1.0 / fast_power_linear(a, -b);
|
2019-12-26 16:30:30 +08:00
|
|
|
|
|
|
|
double result = 1;
|
2020-05-30 07:26:30 +08:00
|
|
|
while (b)
|
|
|
|
{
|
|
|
|
if (b & 1)
|
|
|
|
result = result * a;
|
2019-12-26 16:30:30 +08:00
|
|
|
a = a * a;
|
|
|
|
b = b >> 1;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-05-28 03:14:39 +08:00
|
|
|
/**
|
|
|
|
* Main function
|
|
|
|
*/
|
2020-05-30 07:26:30 +08:00
|
|
|
int main()
|
|
|
|
{
|
2020-05-26 21:05:29 +08:00
|
|
|
std::srand(std::time(nullptr));
|
2019-12-26 16:30:30 +08:00
|
|
|
std::ios_base::sync_with_stdio(false);
|
|
|
|
|
|
|
|
std::cout << "Testing..." << std::endl;
|
2020-05-30 07:26:30 +08:00
|
|
|
for (int i = 0; i < 20; i++)
|
|
|
|
{
|
2020-05-26 21:05:29 +08:00
|
|
|
int a = std::rand() % 20 - 10;
|
|
|
|
int b = std::rand() % 20 - 10;
|
2019-12-26 16:30:30 +08:00
|
|
|
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));
|
|
|
|
|
2020-05-26 21:05:29 +08:00
|
|
|
std::cout << "------ " << a << "^" << b << " = "
|
|
|
|
<< fast_power_recursive(a, b) << std::endl;
|
2019-12-26 16:30:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int64_t a, b;
|
|
|
|
std::cin >> a >> b;
|
|
|
|
|
2020-05-26 21:05:29 +08:00
|
|
|
std::cout << a << "^" << b << " = " << fast_power_recursive(a, b)
|
|
|
|
<< std::endl;
|
2019-12-26 16:30:30 +08:00
|
|
|
|
2020-05-26 21:05:29 +08:00
|
|
|
std::cout << a << "^" << b << " = " << fast_power_linear(a, b) << std::endl;
|
2019-12-26 16:30:30 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|