From 2fcb8474454f613cde693a63771ad8e6cde47c67 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Tue, 12 Nov 2024 16:29:51 -0500 Subject: [PATCH] Express D's flag as "is positive" It's harder to reason about a negative. This code just reads better. --- au/code/au/utility/probable_primes.hh | 16 ++++++++++------ au/code/au/utility/test/probable_primes_test.cc | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/au/code/au/utility/probable_primes.hh b/au/code/au/utility/probable_primes.hh index 99d6d284..fb9715fb 100644 --- a/au/code/au/utility/probable_primes.hh +++ b/au/code/au/utility/probable_primes.hh @@ -185,16 +185,20 @@ constexpr int jacobi_symbol(int64_t raw_a, uint64_t n) { return jacobi_symbol_positive_numerator(a, n, result); } +// The "D" parameter in the Strong Lucas probable prime test. +// +// Default construction produces the first value to try according to Selfridge's parameter +// selection. Calling `increment()` on this will successively produce the next parameter to try. struct LucasDParameter { uint64_t mag = 5u; - bool is_neg = false; + bool is_positive = true; friend constexpr int as_int(const LucasDParameter &D) { - return bool_sign(!D.is_neg) * static_cast(D.mag); + return bool_sign(D.is_positive) * static_cast(D.mag); } friend constexpr void increment(LucasDParameter &D) { D.mag += 2u; - D.is_neg = !D.is_neg; + D.is_positive = !D.is_positive; } }; @@ -205,7 +209,7 @@ struct LucasDParameter { // Requires that `n` is *not* a perfect square. // constexpr LucasDParameter find_first_D_with_jacobi_symbol_neg_one(uint64_t n) { - LucasDParameter D{5u, false}; + LucasDParameter D{}; while (jacobi_symbol(as_int(D), n) != -1) { increment(D); } @@ -232,7 +236,7 @@ constexpr LucasSequenceElement double_strong_lucas_index(const LucasSequenceElem uint64_t V_squared = mul_mod(V, V, n); uint64_t D_U_squared = mul_mod(D.mag, mul_mod(U, U, n), n); uint64_t V2 = - D.is_neg ? sub_mod(V_squared, D_U_squared, n) : add_mod(V_squared, D_U_squared, n); + D.is_positive ? add_mod(V_squared, D_U_squared, n) : sub_mod(V_squared, D_U_squared, n); V2 = half_mod_odd(V2, n); return LucasSequenceElement{ @@ -251,7 +255,7 @@ constexpr LucasSequenceElement increment_strong_lucas_index(const LucasSequenceE auto U2 = half_mod_odd(add_mod(U, V, n), n); const auto D_U = mul_mod(D.mag, U, n); - auto V2 = D.is_neg ? sub_mod(V, D_U, n) : add_mod(V, D_U, n); + auto V2 = D.is_positive ? add_mod(V, D_U, n) : sub_mod(V, D_U, n); V2 = half_mod_odd(V2, n); return LucasSequenceElement{U2, V2}; diff --git a/au/code/au/utility/test/probable_primes_test.cc b/au/code/au/utility/test/probable_primes_test.cc index 9f167be9..8f150dd7 100644 --- a/au/code/au/utility/test/probable_primes_test.cc +++ b/au/code/au/utility/test/probable_primes_test.cc @@ -223,8 +223,8 @@ std::vector strong_lucas_pseudoprimes() { } TEST(LucasDParameter, CanConvertToInt) { - EXPECT_EQ(as_int(LucasDParameter{5u, false}), 5); - EXPECT_EQ(as_int(LucasDParameter{7u, true}), -7); + EXPECT_EQ(as_int(LucasDParameter{5u, true}), 5); + EXPECT_EQ(as_int(LucasDParameter{7u, false}), -7); } TEST(StrongLucas, AllPrimeNumbersAreProbablyPrime) {