Files
even-perfect-numbers-scanner/PerfectNumbers.Core/CycleRemainderStepper.cs
T

85 lines
2.2 KiB
C#

using System.Numerics;
namespace PerfectNumbers.Core;
internal struct CycleRemainderStepper
{
private readonly ulong _cycleLength;
private ulong _previousPrime;
private ulong _currentRemainder;
private bool _hasState;
public CycleRemainderStepper(ulong cycleLength)
{
_cycleLength = cycleLength;
_previousPrime = 0UL;
_currentRemainder = 0UL;
_hasState = false;
}
public bool HasCycle => _cycleLength != 0UL;
public void Reset()
{
_previousPrime = 0UL;
_currentRemainder = 0UL;
_hasState = false;
}
public void InitializeState(ulong previousPrime, ulong previousRemainder, bool hasState)
{
_previousPrime = previousPrime;
_currentRemainder = previousRemainder;
_hasState = hasState;
}
public ulong ComputeNext(ulong prime)
{
if (_cycleLength == 0UL)
{
_previousPrime = prime;
_currentRemainder = 0UL;
_hasState = true;
return 0UL;
}
if (!_hasState || prime <= _previousPrime)
{
_currentRemainder = prime % _cycleLength;
_hasState = true;
}
else
{
ulong delta = prime - _previousPrime;
if (ulong.MaxValue - _currentRemainder < delta)
{
UInt128 extended = (UInt128)_currentRemainder + delta;
_currentRemainder = (ulong)(extended % _cycleLength);
}
else
{
_currentRemainder += delta;
if (_currentRemainder >= _cycleLength)
{
_currentRemainder -= _cycleLength;
if (_currentRemainder >= _cycleLength)
{
_currentRemainder %= _cycleLength;
}
}
}
}
_previousPrime = prime;
return _currentRemainder;
}
public void CaptureState(out ulong previousPrime, out ulong previousRemainder, out bool hasState)
{
previousPrime = _previousPrime;
previousRemainder = _currentRemainder;
hasState = _hasState;
}
}