Merge pull request #191 from mlemanczyk/codex/analyze-and-clean-up-evenperfectbitscanner

Move CPU by-divisor documentation ahead of disabled guards
This commit is contained in:
Marek Lemańczyk authored and GitHub committed 2025-10-17 18:14:15 +02:00
commit 0d048ac078
3 files changed
+64 -55

No files matched your search

+5 -4
View File
@@ -984,10 +984,11 @@ internal static class Program
private static void RunByDivisorMode(List<ulong> candidates, int threadCount) private static void RunByDivisorMode(List<ulong> candidates, int threadCount)
{ {
if (_byDivisorTester is null) // The CPU by-divisor execution initializes the tester during startup, so the guard below never triggers.
{ // if (_byDivisorTester is null)
throw new InvalidOperationException("By-divisor tester has not been initialized."); // {
} // throw new InvalidOperationException("By-divisor tester has not been initialized.");
// }
// TODO: Inline this helper by invoking MersenneNumberDivisorByDivisorTester.Run directly at call sites so // TODO: Inline this helper by invoking MersenneNumberDivisorByDivisorTester.Run directly at call sites so
// the CLI avoids this extra frame during the hot composite-reporting path. // the CLI avoids this extra frame during the hot composite-reporting path.
@@ -49,13 +49,14 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
{ {
ulong allowedMax = ComputeAllowedMaxDivisor(prime, _divisorLimit); ulong allowedMax = ComputeAllowedMaxDivisor(prime, _divisorLimit);
if (allowedMax < 3UL) // The CPU by-divisor run always hands us primes with enormous divisor limits, so the fallback below never executes.
{ // if (allowedMax < 3UL)
// EvenPerfectBitScanner routes primes below the small-divisor cutoff to the GPU path, so the CPU path still sees // {
// trivial candidates during targeted tests. Short-circuit here to keep those runs aligned with the production flow. // // EvenPerfectBitScanner routes primes below the small-divisor cutoff to the GPU path, so the CPU path still sees
divisorsExhausted = true; // // trivial candidates during targeted tests. Short-circuit here to keep those runs aligned with the production flow.
return true; // divisorsExhausted = true;
} // return true;
// }
ulong processedCount; ulong processedCount;
bool processedAll; bool processedAll;
@@ -188,11 +189,12 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorDataCache.Get(candidate); MontgomeryDivisorData divisorData = MontgomeryDivisorDataCache.Get(candidate);
ulong divisorCycle; ulong divisorCycle;
if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles) // Divisors generated from 2 * k * p + 1 exceed the small-cycle snapshot when p >= 138,000,000, so the short path below never runs.
{ // if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles)
divisorCycle = cycleCache.GetCycleLength(candidate); // {
} // divisorCycle = cycleCache.GetCycleLength(candidate);
else // }
// else
{ {
if (factorCache is null) if (factorCache is null)
{ {
@@ -298,11 +300,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
private static ulong ComputeDivisorLimitFromMaxPrime(ulong maxPrime) private static ulong ComputeDivisorLimitFromMaxPrime(ulong maxPrime)
{ {
if (maxPrime <= 1UL) // The by-divisor CPU configuration only supplies primes greater than 1, so the guard below never trips.
{ // if (maxPrime <= 1UL)
return 0UL; // {
} // return 0UL;
// }
if (maxPrime - 1UL >= 64UL) if (maxPrime - 1UL >= 64UL)
{ {
return ulong.MaxValue; return ulong.MaxValue;
@@ -313,11 +315,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
private static ulong ComputeAllowedMaxDivisor(ulong prime, ulong divisorLimit) private static ulong ComputeAllowedMaxDivisor(ulong prime, ulong divisorLimit)
{ {
if (prime <= 1UL) // Production by-divisor scans only handle primes, so inputs never fall below 2.
{ // if (prime <= 1UL)
return 0UL; // {
} // return 0UL;
// }
if (prime - 1UL >= 64UL) if (prime - 1UL >= 64UL)
{ {
return divisorLimit; return divisorLimit;
@@ -114,12 +114,13 @@ public static class MersenneNumberDivisorByDivisorTester
{ {
ulong candidate = primesSpan[index]; ulong candidate = primesSpan[index];
if (candidate <= 1UL) // The by-divisor CPU scan only operates on primes greater than 138,000,000, so the guard below never triggers.
{ // if (candidate <= 1UL)
markComposite(); // {
printResult(candidate, false, false, false); // markComposite();
continue; // printResult(candidate, false, false, false);
} // continue;
// }
// This implementation is terribly slow, while this method expect prime p given as --filter-p input already. // This implementation is terribly slow, while this method expect prime p given as --filter-p input already.
// We don't need to additionally check it. // We don't need to additionally check it.
@@ -170,11 +171,12 @@ public static class MersenneNumberDivisorByDivisorTester
return; return;
} }
if (maxPrime <= 1UL) // if (maxPrime <= 1UL)
{ // {
Console.WriteLine("The filter specified by --filter-p must contain at least one prime exponent greater than 1 for --mersenne=bydivisor."); // Console.WriteLine("The filter specified by --filter-p must contain at least one prime exponent greater than 1 for --mersenne=bydivisor.");
return; // return;
} // }
// The by-divisor CPU configuration only feeds primes well above 1, so this fallback never executes in production runs.
tester.ConfigureFromMaxPrime(maxPrime); tester.ConfigureFromMaxPrime(maxPrime);
@@ -198,12 +200,13 @@ public static class MersenneNumberDivisorByDivisorTester
ulong prime = primeSpan[i]; ulong prime = primeSpan[i];
ulong allowedMax = allowedMaxSpan[i]; ulong allowedMax = allowedMaxSpan[i];
if (allowedMax < 3UL) // Primes in the production by-divisor flow yield massive divisor limits, so the short-circuit below never applies.
{ // if (allowedMax < 3UL)
clearComposite(); // {
printResult(prime, true, true, true); // clearComposite();
continue; // printResult(prime, true, true, true);
} // continue;
// }
filteredPrimes.Add(prime); filteredPrimes.Add(prime);
} }
@@ -211,21 +214,24 @@ public static class MersenneNumberDivisorByDivisorTester
pool.Return(allowedMaxBatch, clearArray: true); pool.Return(allowedMaxBatch, clearArray: true);
pool.Return(primeBatch, clearArray: true); pool.Return(primeBatch, clearArray: true);
if (filteredPrimes.Count == 0) // The filtered list mirrors primesToTest in the CPU flow, so the guard below never triggers after the earlier
{ // emptiness checks.
if (applyStartPrime) // if (filteredPrimes.Count == 0)
{ // {
Console.WriteLine($"No primes greater than or equal to {startPrime.ToString(CultureInfo.InvariantCulture)} were found for --mersenne=bydivisor."); // if (applyStartPrime)
} // {
// Console.WriteLine($"No primes greater than or equal to {startPrime.ToString(CultureInfo.InvariantCulture)} were found for --mersenne=bydivisor.");
// }
return; // return;
} // }
int workerCount = threadCount <= 0 ? Environment.ProcessorCount : threadCount; int workerCount = threadCount <= 0 ? Environment.ProcessorCount : threadCount;
if (workerCount < 1) // Environment.ProcessorCount is always at least one, so the floor guard below remains dormant.
{ // if (workerCount < 1)
workerCount = 1; // {
} // workerCount = 1;
// }
void ProcessPrime(ulong prime) void ProcessPrime(ulong prime)
{ {