Merge pull request #20 from mlemanczyk/codex/modify-evenperfectbitscanner-to-iterate-primes
Use prime merge iteration for EvenPerfectBitScanner
This commit is contained in:
2 files changed
+98
-22
No files matched your search
@@ -12,4 +12,8 @@
|
||||
<_Parameter1>EvenPerfectBitScanner.Tests</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Open.Numeric" Version="3.0.1" />
|
||||
<PackageReference Include="Open.Numeric.Primes" Version="4.0.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Open.Numeric.Primes;
|
||||
using PerfectNumbers.Core;
|
||||
using PerfectNumbers.Core.Gpu;
|
||||
|
||||
@@ -30,7 +31,13 @@ internal static class Program
|
||||
private static MersenneNumberDivisorGpuTester? _divisorTester;
|
||||
private static ulong? _orderWarmupLimitOverride;
|
||||
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 string? _resultsDir;
|
||||
private static string? _resultsPrefix;
|
||||
@@ -569,7 +576,7 @@ internal static class Program
|
||||
}
|
||||
|
||||
Console.WriteLine("Starting scan...");
|
||||
_state = ((long)currentP << 3) | (long)remainder;
|
||||
InitializePrimeMerge(currentP, remainder);
|
||||
Task[] tasks = new Task[threadCount];
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
[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)]
|
||||
private static unsafe int ReserveBlock(ulong[] buffer, int blockSize)
|
||||
{
|
||||
Span<ulong> bufferSpan = new(buffer);
|
||||
ulong p, remainder;
|
||||
long state, newState, original;
|
||||
int count;
|
||||
while (true)
|
||||
{
|
||||
state = Volatile.Read(ref _state);
|
||||
p = (ulong)state >> 3;
|
||||
remainder = ((ulong)state) & 7UL;
|
||||
int count = 0;
|
||||
|
||||
count = 0;
|
||||
while (count < blockSize && !Volatile.Read(ref _limitReached))
|
||||
lock (PrimeMergeSync)
|
||||
{
|
||||
bufferSpan[count++] = p;
|
||||
p = _transformP(p, ref remainder);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
if (!_hasNextPrime && !MoveToNextPrime())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
newState = ((long)p << 3) | (long)remainder;
|
||||
original = Interlocked.CompareExchange(ref _state, newState, state);
|
||||
if (original == state)
|
||||
while (count < blockSize && !Volatile.Read(ref _limitReached))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect)
|
||||
|
||||
Reference in new issue
Block a user