BigInteger-friendly steppers added. MersenneResidueStepper converted to struct. Manual residue tracking replaced with steppers. Modulo operations replaced with steppers.
This commit is contained in:
1 parent
fbf074ade0
commit
6887111128
9 files changed
+238
-421
No files matched your search
@@ -2,37 +2,20 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace PerfectNumbers.Core;
|
||||
|
||||
public struct CycleRemainderStepper
|
||||
public struct CycleRemainderStepper(ulong cycleLength)
|
||||
{
|
||||
private readonly ulong _cycleLength;
|
||||
private ulong _previousPrime;
|
||||
private ulong _currentRemainder;
|
||||
private bool _hasState;
|
||||
|
||||
public CycleRemainderStepper(ulong cycleLength)
|
||||
{
|
||||
if (cycleLength == 0UL)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(cycleLength), "Cycle length must be non-zero.");
|
||||
}
|
||||
|
||||
_cycleLength = cycleLength;
|
||||
_previousPrime = 0UL;
|
||||
_currentRemainder = 0UL;
|
||||
_hasState = false;
|
||||
}
|
||||
private readonly ulong _cycleLength = cycleLength;
|
||||
private ulong _previousPrime = 0UL;
|
||||
private ulong _currentRemainder = 0UL;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Reset()
|
||||
{
|
||||
// TODO: Inline this reset at the call sites so the hot loops reuse struct reinitialization
|
||||
// measured fastest in MersenneDivisorCycleLengthGpuBenchmarks, avoiding the extra
|
||||
// method call when scanners need to restart stepping.
|
||||
_previousPrime = 0UL;
|
||||
_currentRemainder = 0UL;
|
||||
_hasState = false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ulong Initialize(ulong prime)
|
||||
{
|
||||
ulong cycleLength = _cycleLength;
|
||||
@@ -44,24 +27,15 @@ public struct CycleRemainderStepper
|
||||
// MersenneDivisorCycleLengthGpuBenchmarks winner for both CPU and GPU call sites.
|
||||
remainder %= cycleLength;
|
||||
}
|
||||
|
||||
_previousPrime = prime;
|
||||
_currentRemainder = remainder;
|
||||
_hasState = true;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ulong ComputeNext(ulong prime)
|
||||
{
|
||||
if (!_hasState)
|
||||
{
|
||||
throw new InvalidOperationException("CycleRemainderStepper must be initialized before computing.");
|
||||
}
|
||||
|
||||
if (prime <= _previousPrime)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(prime), "Primes must be processed in strictly increasing order.");
|
||||
}
|
||||
|
||||
ulong cycleLength = _cycleLength;
|
||||
ulong delta = prime - _previousPrime;
|
||||
_previousPrime = prime;
|
||||
@@ -90,13 +64,4 @@ public struct CycleRemainderStepper
|
||||
}
|
||||
return _currentRemainder;
|
||||
}
|
||||
|
||||
public void CaptureState(out ulong previousPrime, out ulong previousRemainder, out bool hasState)
|
||||
{
|
||||
// TODO: Expose these fields directly once the residue scanners adopt the single-cycle helper
|
||||
// so the hot path can read them without paying for an additional wrapper call per iteration.
|
||||
previousPrime = _previousPrime;
|
||||
previousRemainder = _currentRemainder;
|
||||
hasState = _hasState;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user