BigInteger-friendly steppers added. MersenneResidueStepper converted to struct. Manual residue tracking replaced with steppers. Modulo operations replaced with steppers.

This commit is contained in:
mlemanczyk committed 2025-12-07 19:16:45 +01:00
1 parent fbf074ade0
commit 6887111128
9 files changed
+238 -421

No files matched your search

+7 -42
View File
@@ -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;
}
}