From d4734356e92d31f4c1a3b235e4370f39a87a3b60 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 3 Dec 2014 15:15:15 -0800 Subject: [PATCH] Added more general power functionality as requested by Sean Parent. Also added enable_if to make sure the exponent is an integral type. --- include/boost/algorithm/algorithm.hpp | 70 ++++++++++++++++++++------- test/Jamfile.v2 | 1 + test/power_fail1.cpp | 24 +++++++++ test/power_test.cpp | 27 +++++------ 4 files changed, 91 insertions(+), 31 deletions(-) create mode 100644 test/power_fail1.cpp diff --git a/include/boost/algorithm/algorithm.hpp b/include/boost/algorithm/algorithm.hpp index 3304831..0cf6c45 100644 --- a/include/boost/algorithm/algorithm.hpp +++ b/include/boost/algorithm/algorithm.hpp @@ -18,32 +18,68 @@ #define BOOST_ALGORITHM_HPP #include // for boost::disable_if +#include namespace boost { namespace algorithm { +template +T identity_operation ( std::multiplies ) { return T(1); } + +template +T identity_operation ( std::plus ) { return T(0); } + + /// \fn power ( T x, Integer n ) /// \return the value "x" raised to the power "n" /// /// \param x The value to be exponentiated -/// \param n The exponent +/// \param n The exponent (must be >= 0) /// -// \remark Taken from Knuth, The Art of Computer Programming, Volume 2: -// Seminumerical Algorithms, Section 4.6.3 +// \remark Taken from Knuth, The Art of Computer Programming, Volume 2: +// Seminumerical Algorithms, Section 4.6.3 template -T power (T x, Integer n) { - T y = 1; // Should be "T y{1};" - if (n == 0) return y; - while (true) { - if (n % 2 == 1) { - y = x * y; - if (n == 1) - return y; - } - n = n / 2; - x = x * x; - } - return y; - } +typename boost::enable_if, T>::type +power (T x, Integer n) { + T y = 1; // Should be "T y{1};" + if (n == 0) return y; + while (true) { + if (n % 2 == 1) { + y = x * y; + if (n == 1) + return y; + } + n = n / 2; + x = x * x; + } + return y; + } + +/// \fn power ( T x, Integer n, Operation op ) +/// \return the value "x" raised to the power "n" +/// using the operaton "op". +/// +/// \param x The value to be exponentiated +/// \param n The exponent (must be >= 0) +/// \param op The operation used +/// +// \remark Taken from Knuth, The Art of Computer Programming, Volume 2: +// Seminumerical Algorithms, Section 4.6.3 +template +typename boost::enable_if, T>::type +power (T x, Integer n, Operation op) { + T y = identity_operation(op); + if (n == 0) return y; + while (true) { + if (n % 2 == 1) { + y = op(x, y); + if (n == 1) + return y; + } + n = n / 2; + x = op(x, x); + } + return y; + } }} diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 727cada..9b5d30b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -30,6 +30,7 @@ alias unit_test_framework # Misc tests [ run clamp_test.cpp unit_test_framework : : : : clamp_test ] [ run power_test.cpp unit_test_framework : : : : power_test ] + [ compile-fail power_fail1.cpp : : : : ] # Cxx11 tests [ run all_of_test.cpp unit_test_framework : : : : all_of_test ] diff --git a/test/power_fail1.cpp b/test/power_fail1.cpp new file mode 100644 index 0000000..6a3bf5f --- /dev/null +++ b/test/power_fail1.cpp @@ -0,0 +1,24 @@ +/* + Copyright (c) Marshall Clow 2014. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#include + +#include +#include + +#define BOOST_TEST_MAIN +#include + +namespace ba = boost::algorithm; + +BOOST_AUTO_TEST_CASE( test_main ) +{ +// Second argument must be an integral value + BOOST_CHECK ( ba::power(1, 1.0) == 1); +} diff --git a/test/power_test.cpp b/test/power_test.cpp index b4d8cf9..20204c1 100644 --- a/test/power_test.cpp +++ b/test/power_test.cpp @@ -15,22 +15,21 @@ #define BOOST_TEST_MAIN #include -#include -#include -#include - namespace ba = boost::algorithm; BOOST_AUTO_TEST_CASE( test_main ) { - BOOST_CHECK ( ba::power(0, 0) == 1); - BOOST_CHECK ( ba::power(5, 0) == 1); - BOOST_CHECK ( ba::power(1, 1) == 1); - BOOST_CHECK ( ba::power(1, 4) == 1); - BOOST_CHECK ( ba::power(3, 2) == 9); - BOOST_CHECK ( ba::power(2, 3) == 8); - BOOST_CHECK ( ba::power(3, 3) == 27); - BOOST_CHECK ( ba::power(2, 30) == 0x40000000); - BOOST_CHECK ( ba::power(5L, 10) == 3125*3125); - BOOST_CHECK ( ba::power(18, 3) == 18*18*18); + BOOST_CHECK ( ba::power(0, 0) == 1); + BOOST_CHECK ( ba::power(5, 0) == 1); + BOOST_CHECK ( ba::power(1, 1) == 1); + BOOST_CHECK ( ba::power(1, 4) == 1); + BOOST_CHECK ( ba::power(3, 2) == 9); + BOOST_CHECK ( ba::power(2, 3) == 8); + BOOST_CHECK ( ba::power(3, 3) == 27); + BOOST_CHECK ( ba::power(2, 30) == 0x40000000); + BOOST_CHECK ( ba::power(5L, 10) == 3125*3125); + BOOST_CHECK ( ba::power(18, 3) == 18*18*18); + + BOOST_CHECK ( ba::power(3,2) == ba::power(3,2, std::multiplies())); + BOOST_CHECK ( ba::power(3,2, std::plus()) == 6); }