diff --git a/PerfectNumbers.Core/UInt128Extensions.cs b/PerfectNumbers.Core/UInt128Extensions.cs index 5a0c093..91e596a 100644 --- a/PerfectNumbers.Core/UInt128Extensions.cs +++ b/PerfectNumbers.Core/UInt128Extensions.cs @@ -634,17 +634,19 @@ public static class UInt128Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static UInt128 AddMod(this UInt128 value, UInt128 addend, UInt128 modulus) { - // The by-divisor CPU path never supplies moduli below 2, so this guard stays disabled. + // All current CPU callers (Pollard Rho and the Mersenne residue tracker) only supply moduli + // of at least three, so leave this guard documented but disabled. // if (modulus <= UInt128.One) // { // return UInt128.Zero; // } - // value and addend already lie below the modulus throughout the divisor-by-divisor CPU flow, - // so skip the redundant reductions the old helper performed. + // Both operands arrive pre-reduced on these paths, letting us skip the redundant folds the old + // helper performed. // value %= modulus; // addend %= modulus; - // Odd moduli keep 2^delta from landing on zero, leaving this branch inactive in the scan. + // Pollard Rho keeps its polynomial constant inside [1, modulus - 1], and the Mersenne pow-delta + // term never hits zero for odd moduli, leaving this branch inactive outside targeted tests. // if (addend == UInt128.Zero) // { // return value; @@ -664,7 +666,8 @@ public static class UInt128Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static UInt128 SubtractOneMod(this UInt128 value, UInt128 modulus) { - // The divisor scan never observes moduli below 2, so leave this guard documented but inactive. + // Only the Mersenne residue tracker calls this helper, and it never observes moduli below three, + // so leave this guard documented but inactive. // if (modulus <= UInt128.One) // { // return UInt128.Zero; @@ -672,6 +675,7 @@ public static class UInt128Extensions if (value == UInt128.Zero) { + // Wrapping occurs when the prior AddMod call produced one, so step back to modulus - 1. return modulus - UInt128.One; } diff --git a/PerfectNumbers.Core/ULongExtensions.cs b/PerfectNumbers.Core/ULongExtensions.cs index 2de1e01..fdd9f07 100644 --- a/PerfectNumbers.Core/ULongExtensions.cs +++ b/PerfectNumbers.Core/ULongExtensions.cs @@ -458,13 +458,14 @@ public static partial class ULongExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong AddMod64(this ulong value, ulong addend, ulong modulus) { - // The CPU factoring path never presents moduli below 2, so leave this guard documented but disabled. + // Every CPU caller (Pollard Rho and the ModPow64 ladder) supplies moduli of at least three, so leave this guard + // documented but disabled. // if (modulus <= 1UL) // { // return 0UL; // } - // The Pollard Rho walks keep both operands below the modulus, so skip re-folding them here. + // Both flows keep their operands below the modulus ahead of time, letting us skip the re-fold the old helper performed. UInt128 sum = (UInt128)value + addend; if (sum < modulus) { @@ -484,7 +485,7 @@ public static partial class ULongExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ulong FoldMontgomery(ulong value, ulong modulus) { - // Moduli in the divisor scan always exceed 1, so retain the documentation and skip the runtime guard. + // Pollard Rho and ModPow64 both feed moduli of at least three, so retain the documentation and skip the runtime guard. // if (modulus <= 1UL) // { // return 0UL; @@ -513,7 +514,7 @@ public static partial class ULongExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ModPow64(this ulong value, ulong exponent, ulong modulus) { - // Moduli below 2 do not occur in the even-perfect divisor scans, so keep the guard commented for clarity. + // Pollard Rho and the Mersenne testers never pass moduli below two, so keep the guard commented for clarity. // if (modulus <= 1UL) // { // return 0UL;