63 lines
1.4 KiB
C#
63 lines
1.4 KiB
C#
using System.Runtime.CompilerServices;
|
|
|
|
namespace PerfectNumbers.Core;
|
|
|
|
public struct BidirectionalCycleRemainderStepper(ulong modulus)
|
|
{
|
|
private readonly ulong _modulus = modulus;
|
|
private ulong _previous = 0UL;
|
|
private ulong _remainder = 0UL;
|
|
|
|
public readonly ulong Modulus
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
|
get
|
|
{
|
|
return _modulus;
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
|
public void Initialize(ulong value)
|
|
{
|
|
_remainder = value.ReduceCycleRemainder(_modulus);
|
|
_previous = value;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
|
public ulong Step(ulong value)
|
|
{
|
|
long delta = unchecked((long)value - (long)_previous);
|
|
_previous = value;
|
|
if (delta == 0)
|
|
{
|
|
return _remainder;
|
|
}
|
|
|
|
if (delta > 0)
|
|
{
|
|
ulong step = ((ulong)delta).ReduceCycleRemainder(_modulus);
|
|
ulong sum = _remainder + step;
|
|
if (sum >= _modulus)
|
|
{
|
|
sum -= _modulus;
|
|
}
|
|
|
|
_remainder = sum;
|
|
return _remainder;
|
|
}
|
|
|
|
ulong backward = ((ulong)-delta).ReduceCycleRemainder(_modulus);
|
|
if (backward > _remainder)
|
|
{
|
|
ulong diff = backward - _remainder;
|
|
ulong wrap = diff.ReduceCycleRemainder(_modulus);
|
|
_remainder = wrap == 0 ? 0UL : _modulus - wrap;
|
|
return _remainder;
|
|
}
|
|
|
|
_remainder -= backward;
|
|
return _remainder;
|
|
}
|
|
}
|