Additional checks will be skipped in bydivisor mode to speed up calculations. Console output extended.

This commit is contained in:
Marek Lemańczyk committed 2025-09-21 14:23:56 +02:00
1 parent 562d2adc3e
commit d117921c3a
2 files changed
+241 -231

No files matched your search

+234 -231
View File
@@ -54,30 +54,30 @@ internal static class Program
private static double _zeroFracConj = -1.0; // disabled when < 0 private static double _zeroFracConj = -1.0; // disabled when < 0
private static int _maxZeroConj = -1; // disabled when < 0 private static int _maxZeroConj = -1; // disabled when < 0
private struct ByDivisorPrimeState private struct ByDivisorPrimeState
{ {
internal ulong Prime; internal ulong Prime;
internal ulong AllowedMax; internal ulong AllowedMax;
internal bool Completed; internal bool Completed;
internal bool Composite; internal bool Composite;
internal bool DetailedCheck; internal bool DetailedCheck;
} }
private readonly struct PendingResult private readonly struct PendingResult
{ {
internal PendingResult(ulong prime, bool detailedCheck, bool passedAllTests) internal PendingResult(ulong prime, bool detailedCheck, bool passedAllTests)
{ {
Prime = prime; Prime = prime;
DetailedCheck = detailedCheck; DetailedCheck = detailedCheck;
PassedAllTests = passedAllTests; PassedAllTests = passedAllTests;
} }
internal ulong Prime { get; } internal ulong Prime { get; }
internal bool DetailedCheck { get; } internal bool DetailedCheck { get; }
internal bool PassedAllTests { get; } internal bool PassedAllTests { get; }
} }
private static unsafe void Main(string[] args) private static unsafe void Main(string[] args)
{ {
@@ -660,9 +660,9 @@ internal static class Program
Console.WriteLine("Starting scan..."); Console.WriteLine("Starting scan...");
if (_useByDivisorMode) if (_useByDivisorMode)
{ {
RunByDivisorMode(filterList, divisorCyclesSearchLimit, threadCount); RunByDivisorMode(filterList, divisorCyclesSearchLimit, threadCount);
FlushBuffer(); FlushBuffer();
StringBuilderPool.Return(_outputBuilder!); StringBuilderPool.Return(_outputBuilder!);
return; return;
@@ -750,12 +750,12 @@ internal static class Program
StringBuilderPool.Return(_outputBuilder!); StringBuilderPool.Return(_outputBuilder!);
} }
private static void RunByDivisorMode(List<ulong> primes, ulong divisorCyclesSearchLimit, int threadCount) private static void RunByDivisorMode(List<ulong> primes, ulong divisorCyclesSearchLimit, int threadCount)
{ {
if (primes.Count == 0) if (primes.Count == 0)
{ {
return; return;
} }
List<ByDivisorPrimeState> states = new(primes.Count); List<ByDivisorPrimeState> states = new(primes.Count);
@@ -788,232 +788,232 @@ internal static class Program
_byDivisorPrecheckOnly = false; _byDivisorPrecheckOnly = false;
if (states.Count == 0) if (states.Count == 0)
{ {
return; return;
} }
object stateLock = new(); object stateLock = new();
ulong divisorLimit = _byDivisorTester!.DivisorLimit; ulong divisorLimit = _byDivisorTester!.DivisorLimit;
ulong nextDivisor = 3UL; ulong nextDivisor = 3UL;
bool divisorsExhausted = false; bool divisorsExhausted = false;
ulong finalDivisorValue = 3UL; ulong finalDivisorValue = 3UL;
int remainingStates = states.Count; int remainingStates = states.Count;
Task[] workers = new Task[Math.Max(1, threadCount)]; Task[] workers = new Task[Math.Max(1, threadCount)];
for (int i = 0; i < workers.Length; i++) for (int i = 0; i < workers.Length; i++)
{ {
workers[i] = Task.Run(() => workers[i] = Task.Run(() =>
{ {
using var session = _byDivisorTester!.CreateDivisorSession(); using var session = _byDivisorTester!.CreateDivisorSession();
byte[] hitsBuffer = ArrayPool<byte>.Shared.Rent(states.Count); byte[] hitsBuffer = ArrayPool<byte>.Shared.Rent(states.Count);
ulong[] primeBuffer = ArrayPool<ulong>.Shared.Rent(states.Count); ulong[] primeBuffer = ArrayPool<ulong>.Shared.Rent(states.Count);
int[] indexBuffer = ArrayPool<int>.Shared.Rent(states.Count); int[] indexBuffer = ArrayPool<int>.Shared.Rent(states.Count);
List<PendingResult> completions = new(states.Count); List<PendingResult> completions = new(states.Count);
List<PendingResult> composites = new(states.Count); List<PendingResult> composites = new(states.Count);
try try
{ {
while (true) while (true)
{ {
ulong divisor; ulong divisor;
int activeCount; int activeCount;
bool shouldTerminate; bool shouldTerminate;
bool hasWork; bool hasWork;
lock (stateLock) lock (stateLock)
{ {
hasWork = TryAcquireDivisorWork(states, divisorLimit, primeBuffer, indexBuffer, completions, ref nextDivisor, ref divisorsExhausted, ref finalDivisorValue, ref remainingStates, out divisor, out activeCount, out shouldTerminate); hasWork = TryAcquireDivisorWork(states, divisorLimit, primeBuffer, indexBuffer, completions, ref nextDivisor, ref divisorsExhausted, ref finalDivisorValue, ref remainingStates, out divisor, out activeCount, out shouldTerminate);
} }
if (completions.Count > 0) if (completions.Count > 0)
{ {
foreach (PendingResult result in completions) foreach (PendingResult result in completions)
{ {
PrintResult(result.Prime, searchedMersenne: true, detailedCheck: result.DetailedCheck, passedAllTests: result.PassedAllTests); PrintResult(result.Prime, searchedMersenne: true, detailedCheck: result.DetailedCheck, passedAllTests: result.PassedAllTests);
} }
completions.Clear(); completions.Clear();
} }
if (!hasWork) if (!hasWork)
{ {
if (shouldTerminate) if (shouldTerminate)
{ {
break; break;
} }
continue; continue;
} }
Span<byte> hitsSpan = hitsBuffer.AsSpan(0, activeCount); Span<byte> hitsSpan = hitsBuffer.AsSpan(0, activeCount);
hitsSpan.Clear(); hitsSpan.Clear();
session.CheckDivisor(divisor, primeBuffer.AsSpan(0, activeCount), hitsSpan); session.CheckDivisor(divisor, primeBuffer.AsSpan(0, activeCount), hitsSpan);
bool exitAfterIteration; bool exitAfterIteration;
composites.Clear(); composites.Clear();
lock (stateLock) lock (stateLock)
{ {
for (int j = 0; j < activeCount; j++) for (int j = 0; j < activeCount; j++)
{ {
if (hitsSpan[j] == 0) if (hitsSpan[j] == 0)
{ {
continue; continue;
} }
int index = indexBuffer[j]; int index = indexBuffer[j];
var state = states[index]; var state = states[index];
if (state.Completed) if (state.Completed)
{ {
continue; continue;
} }
state.Completed = true; state.Completed = true;
state.Composite = true; state.Composite = true;
state.DetailedCheck = true; state.DetailedCheck = true;
states[index] = state; states[index] = state;
remainingStates--; remainingStates--;
composites.Add(new PendingResult(state.Prime, state.DetailedCheck, false)); composites.Add(new PendingResult(state.Prime, state.DetailedCheck, false));
} }
exitAfterIteration = remainingStates == 0; exitAfterIteration = remainingStates == 0;
if (exitAfterIteration && !divisorsExhausted) if (exitAfterIteration && !divisorsExhausted)
{ {
divisorsExhausted = true; divisorsExhausted = true;
finalDivisorValue = Math.Max(finalDivisorValue, nextDivisor); finalDivisorValue = Math.Max(finalDivisorValue, nextDivisor);
} }
} }
if (composites.Count > 0) if (composites.Count > 0)
{ {
foreach (PendingResult result in composites) foreach (PendingResult result in composites)
{ {
PrintResult(result.Prime, searchedMersenne: true, detailedCheck: result.DetailedCheck, passedAllTests: result.PassedAllTests); PrintResult(result.Prime, searchedMersenne: true, detailedCheck: result.DetailedCheck, passedAllTests: result.PassedAllTests);
} }
} }
if (exitAfterIteration) if (exitAfterIteration)
{ {
break; break;
} }
} }
} }
finally finally
{ {
ArrayPool<int>.Shared.Return(indexBuffer, clearArray: true); ArrayPool<int>.Shared.Return(indexBuffer, clearArray: true);
ArrayPool<ulong>.Shared.Return(primeBuffer, clearArray: true); ArrayPool<ulong>.Shared.Return(primeBuffer, clearArray: true);
ArrayPool<byte>.Shared.Return(hitsBuffer, clearArray: true); ArrayPool<byte>.Shared.Return(hitsBuffer, clearArray: true);
} }
}); });
} }
Task.WaitAll(workers); Task.WaitAll(workers);
} }
private static bool TryAcquireDivisorWork(List<ByDivisorPrimeState> states, ulong divisorLimit, ulong[] primeBuffer, int[] indexBuffer, List<PendingResult> completions, ref ulong nextDivisor, ref bool divisorsExhausted, ref ulong finalDivisorValue, ref int remainingStates, out ulong divisor, out int activeCount, out bool shouldTerminate) private static bool TryAcquireDivisorWork(List<ByDivisorPrimeState> states, ulong divisorLimit, ulong[] primeBuffer, int[] indexBuffer, List<PendingResult> completions, ref ulong nextDivisor, ref bool divisorsExhausted, ref ulong finalDivisorValue, ref int remainingStates, out ulong divisor, out int activeCount, out bool shouldTerminate)
{ {
completions.Clear(); completions.Clear();
while (true) while (true)
{ {
if (remainingStates == 0) if (remainingStates == 0)
{ {
divisor = 0UL; divisor = 0UL;
activeCount = 0; activeCount = 0;
shouldTerminate = true; shouldTerminate = true;
return false; return false;
} }
if (divisorsExhausted || nextDivisor > divisorLimit) if (divisorsExhausted || nextDivisor > divisorLimit)
{ {
if (!divisorsExhausted) if (!divisorsExhausted)
{ {
divisorsExhausted = true; divisorsExhausted = true;
finalDivisorValue = nextDivisor; finalDivisorValue = nextDivisor;
} }
ulong completionDivisor = finalDivisorValue; ulong completionDivisor = finalDivisorValue;
for (int i = 0; i < states.Count; i++) for (int i = 0; i < states.Count; i++)
{ {
var state = states[i]; var state = states[i];
if (state.Completed) if (state.Completed)
{ {
continue; continue;
} }
state.Completed = true; state.Completed = true;
state.DetailedCheck = completionDivisor > state.AllowedMax; state.DetailedCheck = completionDivisor > state.AllowedMax;
states[i] = state; states[i] = state;
remainingStates--; remainingStates--;
completions.Add(new PendingResult(state.Prime, state.DetailedCheck, true)); completions.Add(new PendingResult(state.Prime, state.DetailedCheck, true));
} }
divisor = 0UL; divisor = 0UL;
activeCount = 0; activeCount = 0;
shouldTerminate = true; shouldTerminate = true;
return false; return false;
} }
ulong divisorValue = nextDivisor; ulong divisorValue = nextDivisor;
ulong candidate = divisorValue + 2UL; ulong candidate = divisorValue + 2UL;
if (candidate <= divisorValue) if (candidate <= divisorValue)
{ {
divisorsExhausted = true; divisorsExhausted = true;
finalDivisorValue = divisorValue; finalDivisorValue = divisorValue;
} }
else else
{ {
nextDivisor = candidate; nextDivisor = candidate;
if (nextDivisor > divisorLimit) if (nextDivisor > divisorLimit)
{ {
divisorsExhausted = true; divisorsExhausted = true;
finalDivisorValue = nextDivisor; finalDivisorValue = nextDivisor;
} }
} }
activeCount = 0; activeCount = 0;
for (int i = 0; i < states.Count; i++) for (int i = 0; i < states.Count; i++)
{ {
var state = states[i]; var state = states[i];
if (state.Completed) if (state.Completed)
{ {
continue; continue;
} }
if (state.AllowedMax < divisorValue) if (state.AllowedMax < divisorValue)
{ {
state.Completed = true; state.Completed = true;
state.DetailedCheck = true; state.DetailedCheck = true;
states[i] = state; states[i] = state;
remainingStates--; remainingStates--;
completions.Add(new PendingResult(state.Prime, state.DetailedCheck, true)); completions.Add(new PendingResult(state.Prime, state.DetailedCheck, true));
continue; continue;
} }
primeBuffer[activeCount] = state.Prime; primeBuffer[activeCount] = state.Prime;
indexBuffer[activeCount] = i; indexBuffer[activeCount] = i;
activeCount++; activeCount++;
} }
if (activeCount == 0) if (activeCount == 0)
{ {
if (completions.Count == 0) if (completions.Count == 0)
{ {
continue; continue;
} }
divisor = 0UL; divisor = 0UL;
shouldTerminate = remainingStates == 0 && (divisorsExhausted || nextDivisor > divisorLimit); shouldTerminate = remainingStates == 0 && (divisorsExhausted || nextDivisor > divisorLimit);
return false; return false;
} }
divisor = divisorValue; divisor = divisorValue;
shouldTerminate = false; shouldTerminate = false;
return true; return true;
} }
} }
private static unsafe void LoadResultsFile(string resultsFileName, Action<ulong, bool, bool> lineProcessorAction) private static unsafe void LoadResultsFile(string resultsFileName, Action<ulong, bool, bool> lineProcessorAction)
{ {
@@ -1440,7 +1440,7 @@ internal static class Program
} }
// Fast residue-based composite check for p using small primes // Fast residue-based composite check for p using small primes
if (!_useDivisor && IsCompositeByResidues(p)) if (!_useDivisor && !_useByDivisorMode && IsCompositeByResidues(p))
{ {
searchedMersenne = false; searchedMersenne = false;
detailedCheck = false; detailedCheck = false;
@@ -1450,13 +1450,16 @@ internal static class Program
// If primes-device=gpu, route p primality through GPU-assisted sieve (optional MR later) // If primes-device=gpu, route p primality through GPU-assisted sieve (optional MR later)
// TODO: Add deterministic Miller–Rabin rounds in GPU path for 64-bit range. // TODO: Add deterministic Miller–Rabin rounds in GPU path for 64-bit range.
bool isPrimeP = GpuContextPool.ForceCpu if (!_useByDivisorMode)
? PrimeTesters.Value!.IsPrime(p, CancellationToken.None)
: PrimeTesters.Value!.IsPrimeGpu(p, CancellationToken.None);
if (!isPrimeP)
{ {
_lastCompositeP = true; bool isPrimeP = GpuContextPool.ForceCpu
return false; ? PrimeTesters.Value!.IsPrime(p, CancellationToken.None)
: PrimeTesters.Value!.IsPrimeGpu(p, CancellationToken.None);
if (!isPrimeP)
{
_lastCompositeP = true;
return false;
}
} }
searchedMersenne = true; searchedMersenne = true;
@@ -274,12 +274,19 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
} }
int offset = 0; int offset = 0;
int consoleStatus = 0;
while (offset < primes.Length) while (offset < primes.Length)
{ {
int batchSize = Math.Min(_owner._gpuBatchSize, primes.Length - offset); int batchSize = Math.Min(_owner._gpuBatchSize, primes.Length - offset);
Span<ulong> primeSpan = _primesHost.AsSpan(0, batchSize); Span<ulong> primeSpan = _primesHost.AsSpan(0, batchSize);
primes.Slice(offset, batchSize).CopyTo(primeSpan); primes.Slice(offset, batchSize).CopyTo(primeSpan);
if (++consoleStatus == PerfectNumberConstants.ConsoleInterval)
{
Console.WriteLine($"...processed by-divisor candidate = {primes[0]}");
consoleStatus = 0;
}
var primesView = _primesBuffer.View.SubView(0, batchSize); var primesView = _primesBuffer.View.SubView(0, batchSize);
var hitsView = _hitsBuffer.View.SubView(0, batchSize); var hitsView = _hitsBuffer.View.SubView(0, batchSize);