Restore divisor cycle fallback and enforce session disposal guard

This commit is contained in:
Marek Lemańczyk committed 2025-10-15 21:29:24 +02:00
1 parent 763714307f
commit c99aebdf68
2 files changed
+28 -13

No files matched your search

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