Merge pull request #20 from mlemanczyk/codex/modify-evenperfectbitscanner-to-iterate-primes

Use prime merge iteration for EvenPerfectBitScanner
This commit is contained in:
Marek Lemańczyk authored and GitHub committed 2025-09-15 23:18:17 +02:00
commit 2466661b73
2 files changed
+98 -22

No files matched your search

@@ -12,4 +12,8 @@
<_Parameter1>EvenPerfectBitScanner.Tests</_Parameter1> <_Parameter1>EvenPerfectBitScanner.Tests</_Parameter1>
</AssemblyAttribute> </AssemblyAttribute>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Open.Numeric" Version="3.0.1" />
<PackageReference Include="Open.Numeric.Primes" Version="4.0.4" />
</ItemGroup>
</Project> </Project>
+94 -22
View File
@@ -1,6 +1,7 @@
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using Open.Numeric.Primes;
using PerfectNumbers.Core; using PerfectNumbers.Core;
using PerfectNumbers.Core.Gpu; using PerfectNumbers.Core.Gpu;
@@ -30,7 +31,13 @@ internal static class Program
private static MersenneNumberDivisorGpuTester? _divisorTester; private static MersenneNumberDivisorGpuTester? _divisorTester;
private static ulong? _orderWarmupLimitOverride; private static ulong? _orderWarmupLimitOverride;
private static unsafe delegate*<ulong, ref ulong, ulong> _transformP; private static unsafe delegate*<ulong, ref ulong, ulong> _transformP;
private static long _state; private static readonly object PrimeMergeSync = new();
private static readonly TrialDivision.U64.Memoized PrimeGenerator = new();
private static IEnumerator<ulong>? _primeEnumerator;
private static bool _hasNextPrime;
private static ulong _nextPrime;
private static ulong _currentCandidate;
private static ulong _currentRemainder;
private static bool _limitReached; private static bool _limitReached;
private static string? _resultsDir; private static string? _resultsDir;
private static string? _resultsPrefix; private static string? _resultsPrefix;
@@ -569,7 +576,7 @@ internal static class Program
} }
Console.WriteLine("Starting scan..."); Console.WriteLine("Starting scan...");
_state = ((long)currentP << 3) | (long)remainder; InitializePrimeMerge(currentP, remainder);
Task[] tasks = new Task[threadCount]; Task[] tasks = new Task[threadCount];
for (int i = 0; i < threadCount; i++) for (int i = 0; i < threadCount; i++)
@@ -736,39 +743,104 @@ internal static class Program
return $"even_perfect_bit_scan_inc-{inc}_thr-{threads}_blk-{block}_mers-{mers}_mersdev-{mersenneDevice}_ntt-{ntt}_red-{red}_primesdev-{primesDevice}_{order}_orderdev-{orderDevice}_{gcd}_{work}_gputh-{gpuPrimeThreads}_llslice-{llSlice}_scanb-{gpuScanBatch}_warm-{warmupLimit}.csv"; return $"even_perfect_bit_scan_inc-{inc}_thr-{threads}_blk-{block}_mers-{mers}_mersdev-{mersenneDevice}_ntt-{ntt}_red-{red}_primesdev-{primesDevice}_{order}_orderdev-{orderDevice}_{gcd}_{work}_gputh-{gpuPrimeThreads}_llslice-{llSlice}_scanb-{gpuScanBatch}_warm-{warmupLimit}.csv";
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void InitializePrimeMerge(ulong startCandidate, ulong startRemainder)
{
lock (PrimeMergeSync)
{
_currentCandidate = startCandidate;
_currentRemainder = startRemainder;
InitializePrimeEnumerator(startCandidate);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void InitializePrimeEnumerator(ulong startValue)
{
(_primeEnumerator as IDisposable)?.Dispose();
ulong begin = startValue;
_primeEnumerator = PrimeGenerator.StartingAt(in begin).GetEnumerator();
_hasNextPrime = MoveToNextPrime();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool MoveToNextPrime()
{
if (_primeEnumerator is null)
{
return false;
}
if (_primeEnumerator.MoveNext())
{
_nextPrime = _primeEnumerator.Current;
return true;
}
Volatile.Write(ref _limitReached, true);
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool EnsurePrimeForCandidate(ulong candidate)
{
if (!_hasNextPrime)
{
return false;
}
while (_hasNextPrime && _nextPrime < candidate)
{
_hasNextPrime = MoveToNextPrime();
}
return _hasNextPrime;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe int ReserveBlock(ulong[] buffer, int blockSize) private static unsafe int ReserveBlock(ulong[] buffer, int blockSize)
{ {
Span<ulong> bufferSpan = new(buffer); Span<ulong> bufferSpan = new(buffer);
ulong p, remainder; int count = 0;
long state, newState, original;
int count;
while (true)
{
state = Volatile.Read(ref _state);
p = (ulong)state >> 3;
remainder = ((ulong)state) & 7UL;
count = 0; lock (PrimeMergeSync)
while (count < blockSize && !Volatile.Read(ref _limitReached))
{ {
bufferSpan[count++] = p; if (!_hasNextPrime && !MoveToNextPrime())
p = _transformP(p, ref remainder);
}
if (count == 0)
{ {
return 0; return 0;
} }
newState = ((long)p << 3) | (long)remainder; while (count < blockSize && !Volatile.Read(ref _limitReached))
original = Interlocked.CompareExchange(ref _state, newState, state);
if (original == state)
{ {
ulong candidate = _currentCandidate;
if (!EnsurePrimeForCandidate(candidate))
{
break;
}
if (_hasNextPrime && _nextPrime == candidate)
{
bufferSpan[count++] = candidate;
_hasNextPrime = MoveToNextPrime();
if (!_hasNextPrime)
{
_currentCandidate = _transformP(candidate, ref _currentRemainder);
break;
}
}
_currentCandidate = _transformP(candidate, ref _currentRemainder);
if (Volatile.Read(ref _limitReached))
{
break;
}
}
}
return count; return count;
} }
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect) private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect)