From 73e27326a283a39b7bee99c9382b4bb16c0ef5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Mon, 13 Oct 2025 14:21:22 +0200 Subject: [PATCH] Use plain modular math for single-shot CPU checks --- PerfectNumbers.Core/MersenneDivisorCycles.cs | 4 +-- PerfectNumbers.Core/ULongExtensions.cs | 31 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/PerfectNumbers.Core/MersenneDivisorCycles.cs b/PerfectNumbers.Core/MersenneDivisorCycles.cs index 55d6e81..b058e68 100644 --- a/PerfectNumbers.Core/MersenneDivisorCycles.cs +++ b/PerfectNumbers.Core/MersenneDivisorCycles.cs @@ -109,7 +109,7 @@ public class MersenneDivisorCycles return cycleLength == exponent; } - return exponent.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL; + return exponent.Pow2ModBinaryCpu(divisorData.Modulus) == 1UL; } public static bool CycleEqualsExponentForMersenneCandidate(ulong divisor, in MontgomeryDivisorData divisorData, ulong exponent) @@ -133,7 +133,7 @@ public class MersenneDivisorCycles } } - return exponent.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL; + return exponent.Pow2ModBinaryCpu(divisorData.Modulus) == 1UL; } private static bool IsValidMersenneDivisorCandidate(ulong divisor, ulong exponent) diff --git a/PerfectNumbers.Core/ULongExtensions.cs b/PerfectNumbers.Core/ULongExtensions.cs index 3388983..8fe7905 100644 --- a/PerfectNumbers.Core/ULongExtensions.cs +++ b/PerfectNumbers.Core/ULongExtensions.cs @@ -310,6 +310,37 @@ public static class ULongExtensions return state.MulModWithNativeModulo(b, modulus); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong Pow2ModBinaryCpu(this ulong exponent, ulong modulus) + { + if (modulus <= 1UL) + { + return 0UL; + } + + ulong remainingExponent = exponent; + ulong result = 1UL % modulus; + ulong baseValue = 2UL % modulus; + + while (remainingExponent != 0UL) + { + if ((remainingExponent & 1UL) != 0UL) + { + result = result.MulMod64(baseValue, modulus); + } + + remainingExponent >>= 1; + if (remainingExponent == 0UL) + { + break; + } + + baseValue = baseValue.MulMod64(baseValue, modulus); + } + + return result; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Pow2ModBinaryGpu(this ulong exponent, ulong modulus) {