ExponentRemainderStepperCpu local variables optimized. Cache is now driven by manually calculated key to avoid unnecessary allocations.

This commit is contained in:
mlemanczyk committed 2025-12-11 05:29:19 +01:00
1 parent 131b3265bc
commit 547d43de84
1 file changed
+42 -37
@@ -16,7 +16,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
private readonly ulong _cycleLength = cycleLength; private readonly ulong _cycleLength = cycleLength;
private ulong PreviousExponent = 0UL; private ulong PreviousExponent = 0UL;
private ulong _currentMontgomery = divisor.MontgomeryOne; private ulong _currentMontgomery = divisor.MontgomeryOne;
private static readonly ConcurrentDictionary<(ulong Cycle, ulong Delta), ulong> _cycleDeltaCache = new(); private static readonly ConcurrentDictionary<int, ulong> _cycleDeltaCache = new(20_480, PerfectNumberConstants.MaxQForDivisorCycles);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public readonly bool MatchesDivisor(in MontgomeryDivisorData divisor, ulong cycleLength) public readonly bool MatchesDivisor(in MontgomeryDivisorData divisor, ulong cycleLength)
@@ -68,11 +68,11 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
public ulong ComputeNextCpu(ulong exponent) public ulong ComputeNextCpu(ulong exponent)
{ {
ulong delta = exponent - PreviousExponent; ulong delta = exponent - PreviousExponent;
ulong reducedDelta = ReduceDelta(delta); delta = ReduceDelta(delta);
ulong multiplier = reducedDelta == 0UL delta = delta == 0UL
? _montgomeryOne ? _montgomeryOne
: reducedDelta.Pow2MontgomeryModWindowedKeepMontgomeryCpu(_divisor); : delta.Pow2MontgomeryModWindowedKeepMontgomeryCpu(_divisor);
_currentMontgomery = _currentMontgomery.MontgomeryMultiplyCpu(multiplier, _modulus, _nPrime); _currentMontgomery = _currentMontgomery.MontgomeryMultiplyCpu(delta, _modulus, _nPrime);
PreviousExponent = exponent; PreviousExponent = exponent;
return ReduceCurrent(); return ReduceCurrent();
} }
@@ -88,13 +88,14 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
public bool ComputeNextIsUnity(ulong exponent) public bool ComputeNextIsUnity(ulong exponent)
{ {
ulong delta = exponent - PreviousExponent; ulong delta = exponent - PreviousExponent;
ulong reducedDelta = ReduceDelta(delta);
ulong multiplier = reducedDelta == 0UL
? _montgomeryOne
: reducedDelta.Pow2MontgomeryModWindowedKeepMontgomeryCpu(_divisor);
_currentMontgomery = _currentMontgomery.MontgomeryMultiplyCpu(multiplier, _modulus, _nPrime);
PreviousExponent = exponent; PreviousExponent = exponent;
return _currentMontgomery == _montgomeryOne; delta = ReduceDelta(delta);
delta = delta == 0UL
? _montgomeryOne
: delta.Pow2MontgomeryModWindowedKeepMontgomeryCpu(_divisor);
delta = _currentMontgomery.MontgomeryMultiplyCpu(delta, _modulus, _nPrime);
_currentMontgomery = delta;
return delta == _montgomeryOne;
} }
/// <summary> /// <summary>
@@ -126,26 +127,22 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
public bool TryAdvanceWithMontgomeryDelta(ulong exponent, ulong montgomeryDelta, out bool isUnity) public bool TryAdvanceWithMontgomeryDelta(ulong exponent, ulong montgomeryDelta, out bool isUnity)
{ {
ulong delta = exponent - PreviousExponent; ulong delta = exponent - PreviousExponent;
ulong reducedDelta = ReduceDelta(delta); delta = ReduceDelta(delta);
// Prefer a cycle-reduced powmod so stepping stays aligned with the divisor-cycle cache. // Prefer a cycle-reduced powmod so stepping stays aligned with the divisor-cycle cache.
ulong multiplier; if (delta == 0UL)
if (reducedDelta == 0UL)
{ {
multiplier = _montgomeryOne; montgomeryDelta = _montgomeryOne;
} }
else if (_cycleLength != 0UL) else if (_cycleLength != 0UL)
{ {
multiplier = reducedDelta.Pow2MontgomeryModWindowedKeepMontgomeryCpu(_divisor); montgomeryDelta = delta.Pow2MontgomeryModWindowedKeepMontgomeryCpu(_divisor);
}
else
{
multiplier = montgomeryDelta;
} }
_currentMontgomery = _currentMontgomery.MontgomeryMultiplyCpu(multiplier, _modulus, _nPrime); delta = _currentMontgomery.MontgomeryMultiplyCpu(montgomeryDelta, _modulus, _nPrime);
PreviousExponent = exponent; PreviousExponent = exponent;
isUnity = _currentMontgomery == _montgomeryOne; isUnity = delta == _montgomeryOne;
_currentMontgomery = delta;
return true; return true;
} }
@@ -164,21 +161,29 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private readonly ulong ReduceDelta(ulong delta) private readonly ulong ReduceDelta(ulong delta)
{ {
ulong cycleLength = _cycleLength; ulong cycleLength = _cycleLength;
if (cycleLength == 0UL) if (cycleLength == 0UL)
{ {
return delta; return delta;
} }
var key = (cycleLength, delta); int key = BuildKey(delta, cycleLength);
if (_cycleDeltaCache.TryGetValue(key, out ulong cached)) if (_cycleDeltaCache.TryGetValue(key, out ulong cached))
{ {
return cached; return cached;
} }
ulong reduced = delta.ReduceCycleRemainder(cycleLength); cycleLength = delta.ReduceCycleRemainder(cycleLength);
_cycleDeltaCache.TryAdd(key, reduced); _ = _cycleDeltaCache.TryAdd(key, cycleLength);
return reduced; return cycleLength;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int BuildKey(ulong delta, ulong cycleLength)
{
int h1 = delta.GetHashCode();
int h2 = cycleLength.GetHashCode();
return h1 * 33 ^ h2;
}
} }