From 42e2d32a162c4b733d45d646f38f5f046c388617 Mon Sep 17 00:00:00 2001 From: endorphin-naixu Date: Wed, 30 Oct 2024 18:05:35 +0800 Subject: [PATCH 1/2] docs, test, fix: Fit Fast_Power to contributing guidelines and fix a bug in the algorithm calculating non-positive exponents of 0 --- math/fast_power.cpp | 161 ++++++++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 57 deletions(-) diff --git a/math/fast_power.cpp b/math/fast_power.cpp index c5621cd4ecc..b91e804989b 100644 --- a/math/fast_power.cpp +++ b/math/fast_power.cpp @@ -1,7 +1,8 @@ /** * @file - * @brief Faster computation for \f$a^b\f$ - * + * @brief Exponentiating by squaring is a general method for fast computation of large positive integer powers of a number. + * (https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + *@details * 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: @@ -10,84 +11,130 @@ * \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. + * @author + * @see */ -#include -#include -#include -#include -#include -#include +#include /// for assert +#include /// for std::pow +#include /// for int64_t +#include /// for std::rand +#include /// for std::time +#include /// for IO operations + /** - * algorithm implementation for \f$a^b\f$ + * @namespace math + * @brief algorithm implementation for \f$a^b\f$ */ -template -double fast_power_recursive(T a, 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; - 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. - - double result; - if ((b & 1) == 0) // case1 - result = bottom * bottom; - else // case2 - result = bottom * bottom * a; - return result; -} + +namespace math { + +/** + * @brief Functions for fast computation of large positive integer powers of a number. + * @param a The base + * @param b The exponent + * @returns The result of \f$a^b\f$ + */ + + template + double fast_power_recursive(T a, T b) { + /*When the base number is 0 and the exponent is non-positive, it is defined as meaningless + */ + if(a==0 && b<=0){ + return NAN; + } + + // negative power. a^b = 1 / (a^-b) + if (b < 0) + return 1.0 / fast_power_recursive(a, -b); + + if (b == 0) + return 1; + 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. + + double 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 \f$O(\log N)\f$ */ -template -double fast_power_linear(T a, 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; + template + double fast_power_linear(T a, T b) { + /*When the base number is 0 and the exponent is non-positive, it is defined as meaningless + */ + if(a==0 && b<=0){ + return NAN; + } + + // 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; } - return result; -} + +}// namespace math /** - * Main function + * @brief Self-test implementations + * @returns void */ -int main() { +static void test() { + /* The following program will generate and test 1000 pairs of random base and exponential combinations + (ranging from -10 to 9), simulating power operations. The results of verifying fast_power_recursive(a, b) + and fast_power_linear(a, b) are identical to those of the standard library functions std::pow(a, b) + */ std::srand(std::time(nullptr)); std::ios_base::sync_with_stdio(false); + /*When the exponent is negative, it is often unreliable to use the == operator directly. + When comparing comparison results, we use a small threshold (epsilon) to determine whether they are "close enough." + */ + const double epsilon = 1e-8; - std::cout << "Testing..." << std::endl; - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 1000; i++) { int a = std::rand() % 20 - 10; int b = std::rand() % 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)); + /*When the base number is 0 and the exponent is non-positive, it is defined as meaningless + */ + if(a==0&&b<=0){ + continue; + } + double result_recursive = math::fast_power_recursive(a, b); + double result_linear = math::fast_power_linear(a, b); + double result_pow = std::pow(a, b); - std::cout << "------ " << a << "^" << b << " = " - << fast_power_recursive(a, b) << std::endl; + assert(std::fabs(result_recursive - result_pow) < epsilon); + assert(std::fabs(result_linear - result_pow) < epsilon); } - int64_t a, b; - std::cin >> a >> b; - - std::cout << a << "^" << b << " = " << fast_power_recursive(a, b) - << std::endl; + std::cout << "All tests have successfully passed!\n"; +} - std::cout << a << "^" << b << " = " << fast_power_linear(a, b) << std::endl; +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + // std::cout << math::fast_power_recursive(-10, -10) << "\n"< Date: Thu, 31 Oct 2024 14:01:19 +0800 Subject: [PATCH 2/2] Add algorithm author information --- math/fast_power.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/math/fast_power.cpp b/math/fast_power.cpp index b91e804989b..31caa29bdb0 100644 --- a/math/fast_power.cpp +++ b/math/fast_power.cpp @@ -1,6 +1,7 @@ /** * @file - * @brief Exponentiating by squaring is a general method for fast computation of large positive integer powers of a number. + * @brief Exponentiating by squaring is a general method for fast computation of + *large positive integer powers of a number. * (https://en.wikipedia.org/wiki/Exponentiation_by_squaring) *@details * Program that computes \f$a^b\f$ in \f$O(logN)\f$ time. @@ -9,10 +10,8 @@ * \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. - * @author - * @see + * @author [ibahadiraltun](https://github.com/ibahadiraltun) */ #include /// for assert @@ -27,7 +26,6 @@ * @namespace math * @brief algorithm implementation for \f$a^b\f$ */ - namespace math { /**