diff --git a/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs b/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs index 355a63b..6526104 100644 --- a/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs +++ b/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs @@ -19,10 +19,12 @@ internal sealed class MersenneCpuDivisorScanSession : IMersenneNumberDivisorByDi Span hits) { int length = primes.Length; - if (length == 0) - { - return; - } + // EvenPerfectBitScanner always provides at least one exponent on this path. + // Keep the guard commented out for tests that might reuse the session differently. + // if (length == 0) + // { + // return; + // } MontgomeryDivisorData cachedData = divisorData; if (cachedData.Modulus != divisor) @@ -73,7 +75,7 @@ internal sealed class MersenneCpuDivisorScanSession : IMersenneNumberDivisorByDi { if (_disposed) { - return; + throw new ObjectDisposedException(nameof(MersenneCpuDivisorScanSession), "Divisor scan session disposed twice."); } _disposed = true; diff --git a/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs b/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs index 0bd75fa..4bc941b 100644 --- a/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs +++ b/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs @@ -139,6 +139,8 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv factorCacheLease.EnsureInitialized(ref factorCache); } + DivisorCycleCache cycleCache = DivisorCycleCache.Shared; + byte step10 = (byte)(step % 10UL); byte step8 = (byte)(step % 8UL); byte step5 = (byte)(step % 5UL); @@ -153,8 +155,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv byte remainder7 = (byte)(divisor % 7UL); byte remainder11 = (byte)(divisor % 11UL); - // DivisorCycleCache cycleCache = DivisorCycleCache.Shared; // Do not restore the fallback cache; divisors do not repeat on this path. - // Keep the divisibility filters aligned with the divisor-cycle generator so the // CPU path never requests cycles that were skipped during cache creation. bool lastIsSeven = (prime & 3UL) == 3UL; @@ -171,15 +171,28 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv if (admissible && (remainder8 == 1 || remainder8 == 7) && remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0) { MontgomeryDivisorData divisorData = MontgomeryDivisorDataCache.Get(candidate); - Dictionary? cacheForCycle = null; - if (requireLargeCycleCache && candidate > PerfectNumberConstants.MaxQForDivisorCycles) + ulong divisorCycle; + if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles) { - cacheForCycle = factorCache; + divisorCycle = cycleCache.GetCycleLength(candidate); } - - if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponent(candidate, prime, divisorData, cacheForCycle, cacheForCycle is not null, out ulong divisorCycle)) + else { - divisorCycle = 0UL; + Dictionary? cacheForCycle = requireLargeCycleCache ? factorCache : null; + if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponent( + candidate, + prime, + divisorData, + cacheForCycle, + cacheForCycle is not null, + out ulong computedCycle) || computedCycle == 0UL) + { + divisorCycle = cycleCache.GetCycleLength(candidate); + } + else + { + divisorCycle = computedCycle; + } } if (divisorCycle == prime)