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) {