Skip to content

Commit

Permalink
Add test case and resolve last known overflow
Browse files Browse the repository at this point in the history
The new test would fail without this change!
  • Loading branch information
chiphogg committed Nov 8, 2024
1 parent 36da93c commit e392e09
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 1 deletion.
2 changes: 1 addition & 1 deletion au/code/au/utility/mod.hh
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ constexpr uint64_t mul_mod(uint64_t a, uint64_t b, uint64_t n) {
// Precondition: (a < n).
// Precondition: (n is odd).
constexpr uint64_t half_mod_odd(uint64_t a, uint64_t n) {
return (a / 2u) + ((a % 2u == 0u) ? 0u : (n + 1u) / 2u);
return (a / 2u) + ((a % 2u == 0u) ? 0u : (n / 2u + 1u));
}

// (base ^ exp) % n
Expand Down
22 changes: 22 additions & 0 deletions au/code/au/utility/test/mod_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,28 @@ TEST(HalfModOdd, HalvesSumWithNForOddNumbers) {
EXPECT_EQ(half_mod_odd(9u, 11u), 10u);
}

TEST(HalfModOdd, SameAsMultiplyingByCeilOfNOver2WhenNIsOdd) {
// An interesting test case, which helps us make sense of the operation of "dividing by 2" in
// modular arithmetic. When `n` is odd, `2` has a multiplicative inverse, so we can understand
// "dividing by two" in terms of multiplying by this inverse.
//
// This fails when `n` is even, but so does dividing by 2 generally.
//
// In principle, we could replace our `half_mod_odd` implementation with this, and it would have
// the same preconditions, but there's a chance it would be less efficient (because `mul_mod`
// may recurse multiple times). Also, keeping them separate lets us use this test case as an
// independent check.
std::vector<uint64_t> n_values{9u, 11u, 8723493u, MAX};
for (const auto &n : n_values) {
const auto half_n = n / 2u + 1u;

std::vector<uint64_t> x_values{0u, 1u, 2u, (n / 2u), (n / 2u + 1u), (n - 2u), (n - 1u)};
for (const auto &x : x_values) {
EXPECT_EQ(half_mod_odd(x, n), mul_mod(x, half_n, n));
}
}
}

TEST(PowMod, HandlesSimpleCases) {
auto to_the_eighth = [](uint64_t x) {
x *= x;
Expand Down

0 comments on commit e392e09

Please sign in to comment.