Skip to content

Commit

Permalink
Merge pull request #134 from saxbophone/josh/127-rename-pow-to-ipow
Browse files Browse the repository at this point in the history
Rename pow to ipow, change args
  • Loading branch information
saxbophone authored Feb 18, 2023
2 parents ee8ef34 + 258a5b0 commit 55a4b41
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 21 deletions.
7 changes: 4 additions & 3 deletions arby/include/arby/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace com::saxbophone::arby {
* @todo Work out time-complexity
* @relatedalso Nat
*/
constexpr Nat pow(const Nat& base, const Nat& exponent) {
constexpr Nat ipow(const Nat& base, uintmax_t exponent) {
// use divide-and-conquer recursion to break up huge powers into products of smaller powers
// exponent = 0 is our base case to terminate the recursion
if (exponent == 0) {
Expand All @@ -45,9 +45,10 @@ namespace com::saxbophone::arby {
// exponent = 2 is our final base case, as it seems a waste to leave it to the catch-all case below
return base * base;
}
auto [quotient, remainder] = Nat::divmod(exponent, 2);
auto quotient = exponent / 2;
auto remainder = exponent % 2;
// instead of calculating x^n, do x^(n/2)
Nat power = pow(base, quotient);
Nat power = ipow(base, quotient);
power *= power;
// and multiply by base again if n was odd
if (remainder == 1) {
Expand Down
2 changes: 1 addition & 1 deletion arby/src/Nat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace com::saxbophone::arby {
Nat max_possible;
std::tie(max_possible, std::ignore) = ilog(base, std::numeric_limits<uintmax_t>::max());
// we will build up the string using digits of this base, for efficiency
const Nat chunk = pow(base, max_possible);
const Nat chunk = ipow(base, (uintmax_t)max_possible);
Nat value = *this;
std::string digits;
// build the digits up backwards, least-significant-first up to the most
Expand Down
6 changes: 3 additions & 3 deletions tests/Nat/query_size.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ using namespace com::saxbophone;
TEST_CASE("arby::Nat.digit_length() returns the number of digits used to store the value", "[query-size]") {
auto digits = GENERATE(range(1u, 10u));

arby::Nat value = arby::pow(arby::Nat::BASE, digits - 1);
arby::Nat value = arby::ipow(arby::Nat::BASE, digits - 1);

CHECK(value.digit_length() == digits);
}

TEST_CASE("arby::Nat.byte_length() returns the number of bytes needed to store the value", "[query-size]") {
auto digits = GENERATE(range(1u, 10u));

arby::Nat value = arby::pow(256, digits - 1);
arby::Nat value = arby::ipow(256, digits - 1);

CHECK(value.byte_length() == digits);
}

TEST_CASE("arby::Nat.bit_length() returns the number of bits needed to store the value", "[query-size]") {
auto digits = GENERATE(range(1u, 100u));

arby::Nat value = arby::pow(2, digits - 1);
arby::Nat value = arby::ipow(2, digits - 1);

CHECK(value.bit_length() == digits);
}
13 changes: 6 additions & 7 deletions tests/Nat/stringification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,17 @@ TEST_CASE("Using std::ostream << arby::Nat generates decimal string of value", "
"348043020149049820481084013929310390000000000010001000101010239189777777777774032932032404910921929187129000001009109101000000000000000"
},
{
arby::pow(2, 1000),
arby::ipow(2, 1000),
"10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376"
},
{
arby::pow(2, 2000),
arby::ipow(2, 2000),
"114813069527425452423283320117768198402231770208869520047764273682576626139237031385665948631650626991844596463898746277344711896086305533142593135616665318539129989145312280000688779148240044871428926990063486244781615463646388363947317026040466353970904996558162398808944629605623311649536164221970332681344168908984458505602379484807914058900934776500429002716706625830522008132236281291761267883317206598995396418127021779858404042159853183251540889433902091920554957783589672039160081957216630582755380425583726015528348786419432054508915275783882625175435528800822842770817965453762184851149029376"
},
// Although this case does pass, it takes a few minutes currently:
// {
// arby::pow(2, 4000),
// "13182040934309431001038897942365913631840191610932727690928034502417569281128344551079752123172122033140940756480716823038446817694240581281731062452512184038544674444386888956328970642771993930036586552924249514488832183389415832375620009284922608946111038578754077913265440918583125586050431647284603636490823850007826811672468900210689104488089485347192152708820119765006125944858397761874669301278745233504796586994514054435217053803732703240283400815926169348364799472716094576894007243168662568886603065832486830606125017643356469732407252874567217733694824236675323341755681839221954693820456072020253884371226826844858636194212875139566587445390068014747975813971748114770439248826688667129237954128555841874460665729630492658600179338272579110020881228767361200603478973120168893997574353727653998969223092798255701666067972698906236921628764772837915526086464389161570534616956703744840502975279094087587298968423516531626090898389351449020056851221079048966718878943309232071978575639877208621237040940126912767610658141079378758043403611425454744180577150855204937163460902512732551260539639221457005977247266676344018155647509515396711351487546062479444592779055555421362722504575706910949376"
// },
{
arby::ipow(2, 4000),
"13182040934309431001038897942365913631840191610932727690928034502417569281128344551079752123172122033140940756480716823038446817694240581281731062452512184038544674444386888956328970642771993930036586552924249514488832183389415832375620009284922608946111038578754077913265440918583125586050431647284603636490823850007826811672468900210689104488089485347192152708820119765006125944858397761874669301278745233504796586994514054435217053803732703240283400815926169348364799472716094576894007243168662568886603065832486830606125017643356469732407252874567217733694824236675323341755681839221954693820456072020253884371226826844858636194212875139566587445390068014747975813971748114770439248826688667129237954128555841874460665729630492658600179338272579110020881228767361200603478973120168893997574353727653998969223092798255701666067972698906236921628764772837915526086464389161570534616956703744840502975279094087587298968423516531626090898389351449020056851221079048966718878943309232071978575639877208621237040940126912767610658141079378758043403611425454744180577150855204937163460902512732551260539639221457005977247266676344018155647509515396711351487546062479444592779055555421362722504575706910949376"
},
}
)
);
Expand Down
2 changes: 1 addition & 1 deletion tests/math_support/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
add_library(
math-support OBJECT
ilog.cpp
pow.cpp
ipow.cpp
)
target_link_libraries(math-support PRIVATE tests-config)
target_precompile_headers(math-support PRIVATE <arby/math.hpp>)
12 changes: 6 additions & 6 deletions tests/math_support/pow.cpp → tests/math_support/ipow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@

using namespace com::saxbophone;

TEST_CASE("Any arby::Nat raised to the power of zero returns 1", "[math-support][pow]") {
TEST_CASE("Any arby::Nat raised to the power of zero returns 1", "[math-support][ipow]") {
auto value = GENERATE(take(1000, random((uintmax_t)0, std::numeric_limits<uintmax_t>::max())));

CHECK(arby::pow(arby::Nat(value), arby::Nat(0)) == 1);
CHECK(arby::ipow(arby::Nat(value), 0) == 1);
}

TEST_CASE("Zero raised to the power of any non-zero arby::Nat returns 0", "[math-support][pow]") {
TEST_CASE("Zero raised to the power of any non-zero arby::Nat returns 0", "[math-support][ipow]") {
auto value = GENERATE(take(1000, random((uintmax_t)1, std::numeric_limits<uintmax_t>::max())));

CHECK(arby::pow(arby::Nat(0), arby::Nat(value)) == 0);
CHECK(arby::ipow(arby::Nat(0), value) == 0);
}

// std::pow() is not accurate for large powers and we need exactness
Expand All @@ -36,7 +36,7 @@ static uintmax_t integer_pow(uintmax_t base, uintmax_t exponent) {
return power;
}

TEST_CASE("Non-zero arby::Nat raised to the power of non-zero arby::Nat", "[math-support][pow]") {
TEST_CASE("Non-zero arby::Nat raised to the power of non-zero arby::Nat", "[math-support][ipow]") {
// base needs to be severely constrained if we are to have any reasonable prospect of getting some large exponents
auto base = GENERATE(take(10000, random((uintmax_t)1, (uintmax_t)256)));
// use log-n to find out the maximmum number exponent we can raise base to to fit in uintmax_t range
Expand All @@ -46,5 +46,5 @@ TEST_CASE("Non-zero arby::Nat raised to the power of non-zero arby::Nat", "[math

CAPTURE(base, exponent);

CHECK((uintmax_t)arby::pow(arby::Nat(base), arby::Nat(exponent)) == integer_pow(base, exponent));
CHECK((uintmax_t)arby::ipow(arby::Nat(base), exponent) == integer_pow(base, exponent));
}

0 comments on commit 55a4b41

Please sign in to comment.