Reduce GC in CPU odd power ladder

This commit is contained in:
Marek Lemańczyk committed 2025-10-11 22:45:46 +02:00
1 parent b33158390f
commit 2da549fe8c
1 file changed
+58 -45
+58 -45
View File
@@ -346,48 +346,67 @@ public static class ULongExtensions
ulong result = divisor.MontgomeryOne; ulong result = divisor.MontgomeryOne;
ulong nPrime = divisor.NPrime; ulong nPrime = divisor.NPrime;
ulong[] oddPowers = InitializeMontgomeryOddPowersCpu(divisor, modulus, nPrime, oddPowerCount);
Span<ulong> oddPowerStorage;
ulong[]? pooledOddPowers = null;
if (oddPowerCount <= PerfectNumberConstants.MaxOddPowersCount)
{
oddPowerStorage = stackalloc ulong[PerfectNumberConstants.MaxOddPowersCount];
}
else if (oddPowerCount < PerfectNumberConstants.PooledArrayThreshold)
{
oddPowerStorage = new ulong[oddPowerCount];
}
else
{
pooledOddPowers = ArrayPool<ulong>.Shared.Rent(oddPowerCount);
oddPowerStorage = pooledOddPowers;
}
Span<ulong> oddPowers = oddPowerStorage[..oddPowerCount];
InitializeMontgomeryOddPowersCpu(divisor, modulus, nPrime, oddPowers);
int index = bitLength - 1; int index = bitLength - 1;
while (index >= 0) while (index >= 0)
{ {
if (((exponent >> index) & 1UL) == 0UL) if (((exponent >> index) & 1UL) == 0UL)
{ {
result = result.MontgomeryMultiply(result, modulus, nPrime); result = result.MontgomeryMultiply(result, modulus, nPrime);
index--; index--;
continue; continue;
} }
int windowStart = index - windowSize + 1; int windowStart = index - windowSize + 1;
if (windowStart < 0) if (windowStart < 0)
{ {
windowStart = 0; windowStart = 0;
} }
while (((exponent >> windowStart) & 1UL) == 0UL) while (((exponent >> windowStart) & 1UL) == 0UL)
{ {
windowStart++; windowStart++;
} }
int windowLength = index - windowStart + 1; int windowLength = index - windowStart + 1;
for (int square = 0; square < windowLength; square++) for (int square = 0; square < windowLength; square++)
{ {
result = result.MontgomeryMultiply(result, modulus, nPrime); result = result.MontgomeryMultiply(result, modulus, nPrime);
} }
ulong mask = (1UL << windowLength) - 1UL; ulong mask = (1UL << windowLength) - 1UL;
ulong windowValue = (exponent >> windowStart) & mask; ulong windowValue = (exponent >> windowStart) & mask;
int tableIndex = (int)((windowValue - 1UL) >> 1); int tableIndex = (int)((windowValue - 1UL) >> 1);
ulong multiplier = oddPowers[tableIndex]; ulong multiplier = oddPowers[tableIndex];
result = result.MontgomeryMultiply(multiplier, modulus, nPrime); result = result.MontgomeryMultiply(multiplier, modulus, nPrime);
index = windowStart - 1; index = windowStart - 1;
} }
if (oddPowerCount >= PerfectNumberConstants.PooledArrayThreshold) if (pooledOddPowers is not null)
{ {
ArrayPool<ulong>.Shared.Return(oddPowers); ArrayPool<ulong>.Shared.Return(pooledOddPowers);
} }
if (keepMontgomery) if (keepMontgomery)
{ {
@@ -533,29 +552,25 @@ public static class ULongExtensions
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong[] InitializeMontgomeryOddPowersCpu(in MontgomeryDivisorData divisor, ulong modulus, ulong nPrime, int oddPowerCount) private static void InitializeMontgomeryOddPowersCpu(in MontgomeryDivisorData divisor, ulong modulus, ulong nPrime, Span<ulong> destination)
{ {
ulong[] oddPowers = oddPowerCount < PerfectNumberConstants.PooledArrayThreshold int oddPowerCount = destination.Length;
? new ulong[oddPowerCount]
: ArrayPool<ulong>.Shared.Rent(oddPowerCount);
if (oddPowerCount == 0) if (oddPowerCount == 0)
{ {
return oddPowers; return;
} }
Span<ulong> destination = oddPowers.AsSpan(0, oddPowerCount);
bool computedOnGpu = oddPowerCount <= PerfectNumberConstants.MaxOddPowersCount bool computedOnGpu = oddPowerCount <= PerfectNumberConstants.MaxOddPowersCount
&& MontgomeryOddPowerGpu.TryCompute(divisor, oddPowerCount, destination); && MontgomeryOddPowerGpu.TryCompute(divisor, oddPowerCount, destination);
if (computedOnGpu) if (computedOnGpu)
{ {
return oddPowers; return;
} }
destination[0] = divisor.MontgomeryTwo; destination[0] = divisor.MontgomeryTwo;
if (oddPowerCount == 1) if (oddPowerCount == 1)
{ {
return oddPowers; return;
} }
ulong square = divisor.MontgomeryTwoSquared; ulong square = divisor.MontgomeryTwoSquared;
@@ -565,8 +580,6 @@ public static class ULongExtensions
current = current.MontgomeryMultiply(square, modulus, nPrime); current = current.MontgomeryMultiply(square, modulus, nPrime);
destination[i] = current; destination[i] = current;
} }
return oddPowers;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]