Merge branch 'codex/fix-unhandled-exception-in-evenperfectbitscanner' of https://github.com/mlemanczyk/even-perfect-numbers-scanner into codex/fix-unhandled-exception-in-evenperfectbitscanner
This commit is contained in:
commit
e5f5cd563e
8 files changed
+87
-64
No files matched your search
@@ -32,7 +32,7 @@ public class GpuUInt128Montgomery64Benchmarks
|
|||||||
[Benchmark(Baseline = true)]
|
[Benchmark(Baseline = true)]
|
||||||
public ulong ExtensionMontgomeryMultiply()
|
public ulong ExtensionMontgomeryMultiply()
|
||||||
{
|
{
|
||||||
return Input.Left.MontgomeryMultiply(Input.Right, Input.Modulus, Input.NPrime);
|
return Input.Left.MontgomeryMultiplyCpu(Input.Right, Input.Modulus, Input.NPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ public class Pow2ModBenchmarks
|
|||||||
ulong nPrime = ComputeMontgomeryNPrime(modulus);
|
ulong nPrime = ComputeMontgomeryNPrime(modulus);
|
||||||
ulong montgomeryOne = ComputeMontgomeryResidue(1UL, modulus);
|
ulong montgomeryOne = ComputeMontgomeryResidue(1UL, modulus);
|
||||||
ulong montgomeryTwo = ComputeMontgomeryResidue(2UL, modulus);
|
ulong montgomeryTwo = ComputeMontgomeryResidue(2UL, modulus);
|
||||||
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiply(montgomeryTwo, montgomeryTwo, modulus, nPrime);
|
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiplyCpu(montgomeryTwo, montgomeryTwo, modulus, nPrime);
|
||||||
|
|
||||||
return new MontgomeryDivisorData(
|
return new MontgomeryDivisorData(
|
||||||
modulus,
|
modulus,
|
||||||
@@ -736,22 +736,22 @@ public class Pow2ModBenchmarks
|
|||||||
|
|
||||||
if (exponent == 0UL)
|
if (exponent == 0UL)
|
||||||
{
|
{
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
int msbIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
int msbIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
||||||
|
|
||||||
for (int bitIndex = msbIndex; bitIndex >= 0; bitIndex--)
|
for (int bitIndex = msbIndex; bitIndex >= 0; bitIndex--)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(result, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(result, modulus, nPrime);
|
||||||
|
|
||||||
if (((exponent >> bitIndex) & 1UL) != 0UL)
|
if (((exponent >> bitIndex) & 1UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(baseVal, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(baseVal, modulus, nPrime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong Pow2MontgomeryModBatched4(ulong exponent, in MontgomeryDivisorData divisor)
|
private static ulong Pow2MontgomeryModBatched4(ulong exponent, in MontgomeryDivisorData divisor)
|
||||||
@@ -772,35 +772,35 @@ public class Pow2ModBenchmarks
|
|||||||
ulong nibble = remainingExponent & 0xFUL;
|
ulong nibble = remainingExponent & 0xFUL;
|
||||||
|
|
||||||
ulong base0 = baseVal;
|
ulong base0 = baseVal;
|
||||||
ulong base1 = base0.MontgomeryMultiply(base0, modulus, nPrime);
|
ulong base1 = base0.MontgomeryMultiplyCpu(base0, modulus, nPrime);
|
||||||
ulong base2 = base1.MontgomeryMultiply(base1, modulus, nPrime);
|
ulong base2 = base1.MontgomeryMultiplyCpu(base1, modulus, nPrime);
|
||||||
ulong base3 = base2.MontgomeryMultiply(base2, modulus, nPrime);
|
ulong base3 = base2.MontgomeryMultiplyCpu(base2, modulus, nPrime);
|
||||||
|
|
||||||
if ((nibble & 1UL) != 0UL)
|
if ((nibble & 1UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base0, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base0, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nibble & 2UL) != 0UL)
|
if ((nibble & 2UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base1, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base1, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nibble & 4UL) != 0UL)
|
if ((nibble & 4UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base2, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base2, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nibble & 8UL) != 0UL)
|
if ((nibble & 8UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base3, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base3, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVal = base3.MontgomeryMultiply(base3, modulus, nPrime);
|
baseVal = base3.MontgomeryMultiplyCpu(base3, modulus, nPrime);
|
||||||
remainingExponent >>= 4;
|
remainingExponent >>= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong Pow2MontgomeryModSlidingWindow(ulong exponent, in MontgomeryDivisorData divisor)
|
private static ulong Pow2MontgomeryModSlidingWindow(ulong exponent, in MontgomeryDivisorData divisor)
|
||||||
@@ -817,16 +817,16 @@ public class Pow2ModBenchmarks
|
|||||||
|
|
||||||
if (exponent == 0UL)
|
if (exponent == 0UL)
|
||||||
{
|
{
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int WindowSize = 5;
|
const int WindowSize = 5;
|
||||||
Span<ulong> oddPowers = stackalloc ulong[1 << (WindowSize - 1)];
|
Span<ulong> oddPowers = stackalloc ulong[1 << (WindowSize - 1)];
|
||||||
oddPowers[0] = baseVal;
|
oddPowers[0] = baseVal;
|
||||||
ulong baseSquared = baseVal.MontgomeryMultiply(baseVal, modulus, nPrime);
|
ulong baseSquared = baseVal.MontgomeryMultiplyCpu(baseVal, modulus, nPrime);
|
||||||
for (int i = 1; i < oddPowers.Length; i++)
|
for (int i = 1; i < oddPowers.Length; i++)
|
||||||
{
|
{
|
||||||
oddPowers[i] = oddPowers[i - 1].MontgomeryMultiply(baseSquared, modulus, nPrime);
|
oddPowers[i] = oddPowers[i - 1].MontgomeryMultiplyCpu(baseSquared, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bitIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
int bitIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
||||||
@@ -835,7 +835,7 @@ public class Pow2ModBenchmarks
|
|||||||
{
|
{
|
||||||
if (((exponent >> bitIndex) & 1UL) == 0UL)
|
if (((exponent >> bitIndex) & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(result, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(result, modulus, nPrime);
|
||||||
bitIndex--;
|
bitIndex--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -852,14 +852,14 @@ public class Pow2ModBenchmarks
|
|||||||
int squares = bitIndex - windowStart + 1;
|
int squares = bitIndex - windowStart + 1;
|
||||||
for (int i = 0; i < squares; i++)
|
for (int i = 0; i < squares; i++)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(result, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(result, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = result.MontgomeryMultiply(oddPowers[(int)(windowValue >> 1)], modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(oddPowers[(int)(windowValue >> 1)], modulus, nPrime);
|
||||||
bitIndex = windowStart - 1;
|
bitIndex = windowStart - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong Pow2ModBinary(ulong exponent, ulong modulus)
|
private static ulong Pow2ModBinary(ulong exponent, ulong modulus)
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ public class Pow2MontgomeryModBenchmarks
|
|||||||
ulong nPrime = ComputeMontgomeryNPrime(modulus);
|
ulong nPrime = ComputeMontgomeryNPrime(modulus);
|
||||||
ulong montgomeryOne = ComputeMontgomeryResidue(1UL, modulus);
|
ulong montgomeryOne = ComputeMontgomeryResidue(1UL, modulus);
|
||||||
ulong montgomeryTwo = ComputeMontgomeryResidue(2UL, modulus);
|
ulong montgomeryTwo = ComputeMontgomeryResidue(2UL, modulus);
|
||||||
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiply(montgomeryTwo, montgomeryTwo, modulus, nPrime);
|
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiplyCpu(montgomeryTwo, montgomeryTwo, modulus, nPrime);
|
||||||
|
|
||||||
return new MontgomeryDivisorData(
|
return new MontgomeryDivisorData(
|
||||||
modulus,
|
modulus,
|
||||||
@@ -300,22 +300,22 @@ public class Pow2MontgomeryModBenchmarks
|
|||||||
|
|
||||||
if (exponent == 0UL)
|
if (exponent == 0UL)
|
||||||
{
|
{
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
int msbIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
int msbIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
||||||
|
|
||||||
for (int bitIndex = msbIndex; bitIndex >= 0; bitIndex--)
|
for (int bitIndex = msbIndex; bitIndex >= 0; bitIndex--)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(result, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(result, modulus, nPrime);
|
||||||
|
|
||||||
if (((exponent >> bitIndex) & 1UL) != 0UL)
|
if (((exponent >> bitIndex) & 1UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(baseVal, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(baseVal, modulus, nPrime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong Pow2MontgomeryModBatched4(ulong exponent, in MontgomeryDivisorData divisor)
|
private static ulong Pow2MontgomeryModBatched4(ulong exponent, in MontgomeryDivisorData divisor)
|
||||||
@@ -336,35 +336,35 @@ public class Pow2MontgomeryModBenchmarks
|
|||||||
ulong nibble = remainingExponent & 0xFUL;
|
ulong nibble = remainingExponent & 0xFUL;
|
||||||
|
|
||||||
ulong base0 = baseVal;
|
ulong base0 = baseVal;
|
||||||
ulong base1 = base0.MontgomeryMultiply(base0, modulus, nPrime);
|
ulong base1 = base0.MontgomeryMultiplyCpu(base0, modulus, nPrime);
|
||||||
ulong base2 = base1.MontgomeryMultiply(base1, modulus, nPrime);
|
ulong base2 = base1.MontgomeryMultiplyCpu(base1, modulus, nPrime);
|
||||||
ulong base3 = base2.MontgomeryMultiply(base2, modulus, nPrime);
|
ulong base3 = base2.MontgomeryMultiplyCpu(base2, modulus, nPrime);
|
||||||
|
|
||||||
if ((nibble & 1UL) != 0UL)
|
if ((nibble & 1UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base0, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base0, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nibble & 2UL) != 0UL)
|
if ((nibble & 2UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base1, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base1, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nibble & 4UL) != 0UL)
|
if ((nibble & 4UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base2, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base2, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nibble & 8UL) != 0UL)
|
if ((nibble & 8UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(base3, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(base3, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVal = base3.MontgomeryMultiply(base3, modulus, nPrime);
|
baseVal = base3.MontgomeryMultiplyCpu(base3, modulus, nPrime);
|
||||||
remainingExponent >>= 4;
|
remainingExponent >>= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Update it with the latest implementations
|
// TODO: Update it with the latest implementations
|
||||||
@@ -382,16 +382,16 @@ public class Pow2MontgomeryModBenchmarks
|
|||||||
|
|
||||||
if (exponent == 0UL)
|
if (exponent == 0UL)
|
||||||
{
|
{
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int WindowSize = 5;
|
const int WindowSize = 5;
|
||||||
Span<ulong> oddPowers = stackalloc ulong[1 << (WindowSize - 1)];
|
Span<ulong> oddPowers = stackalloc ulong[1 << (WindowSize - 1)];
|
||||||
oddPowers[0] = baseVal;
|
oddPowers[0] = baseVal;
|
||||||
ulong baseSquared = baseVal.MontgomeryMultiply(baseVal, modulus, nPrime);
|
ulong baseSquared = baseVal.MontgomeryMultiplyCpu(baseVal, modulus, nPrime);
|
||||||
for (int i = 1; i < oddPowers.Length; i++)
|
for (int i = 1; i < oddPowers.Length; i++)
|
||||||
{
|
{
|
||||||
oddPowers[i] = oddPowers[i - 1].MontgomeryMultiply(baseSquared, modulus, nPrime);
|
oddPowers[i] = oddPowers[i - 1].MontgomeryMultiplyCpu(baseSquared, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bitIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
int bitIndex = 63 - BitOperations.LeadingZeroCount(exponent);
|
||||||
@@ -400,7 +400,7 @@ public class Pow2MontgomeryModBenchmarks
|
|||||||
{
|
{
|
||||||
if (((exponent >> bitIndex) & 1UL) == 0UL)
|
if (((exponent >> bitIndex) & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(result, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(result, modulus, nPrime);
|
||||||
bitIndex--;
|
bitIndex--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -417,14 +417,14 @@ public class Pow2MontgomeryModBenchmarks
|
|||||||
int squares = bitIndex - windowStart + 1;
|
int squares = bitIndex - windowStart + 1;
|
||||||
for (int i = 0; i < squares; i++)
|
for (int i = 0; i < squares; i++)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(result, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(result, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = result.MontgomeryMultiply(oddPowers[(int)(windowValue >> 1)], modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(oddPowers[(int)(windowValue >> 1)], modulus, nPrime);
|
||||||
bitIndex = windowStart - 1;
|
bitIndex = windowStart - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Update it with the latest implementations, if it exists in production code. Otherwise just remove TODO
|
// TODO: Update it with the latest implementations, if it exists in production code. Otherwise just remove TODO
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ internal struct ExponentRemainderStepperCpu
|
|||||||
// single-block divisor-cycle snapshot so we can skip the powmod entirely and reuse the
|
// single-block divisor-cycle snapshot so we can skip the powmod entirely and reuse the
|
||||||
// cached Montgomery residue ladder highlighted in MersenneDivisorCycleLengthGpuBenchmarks.
|
// cached Montgomery residue ladder highlighted in MersenneDivisorCycleLengthGpuBenchmarks.
|
||||||
ulong multiplier = delta.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true);
|
ulong multiplier = delta.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true);
|
||||||
_currentMontgomery = _currentMontgomery.MontgomeryMultiply(multiplier, _modulus, _nPrime);
|
_currentMontgomery = _currentMontgomery.MontgomeryMultiplyCpu(multiplier, _modulus, _nPrime);
|
||||||
PreviousExponent = exponent;
|
PreviousExponent = exponent;
|
||||||
return ReduceCurrent();
|
return ReduceCurrent();
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ internal struct ExponentRemainderStepperCpu
|
|||||||
// TODO: Reuse the divisor-cycle derived Montgomery delta once the cache exposes single-cycle
|
// TODO: Reuse the divisor-cycle derived Montgomery delta once the cache exposes single-cycle
|
||||||
// lookups so this branch also avoids recomputing powmods when the snapshot lacks the divisor.
|
// lookups so this branch also avoids recomputing powmods when the snapshot lacks the divisor.
|
||||||
ulong multiplier = delta.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true);
|
ulong multiplier = delta.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true);
|
||||||
_currentMontgomery = _currentMontgomery.MontgomeryMultiply(multiplier, _modulus, _nPrime);
|
_currentMontgomery = _currentMontgomery.MontgomeryMultiplyCpu(multiplier, _modulus, _nPrime);
|
||||||
PreviousExponent = exponent;
|
PreviousExponent = exponent;
|
||||||
return _currentMontgomery == _montgomeryOne;
|
return _currentMontgomery == _montgomeryOne;
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ internal struct ExponentRemainderStepperCpu
|
|||||||
// TODO: Once the divisor-cycle cache exposes a direct Montgomery delta, multiply it here instead
|
// TODO: Once the divisor-cycle cache exposes a direct Montgomery delta, multiply it here instead
|
||||||
// of relying on the caller-provided delta so incremental scans remain in sync with the snapshot
|
// of relying on the caller-provided delta so incremental scans remain in sync with the snapshot
|
||||||
// without computing additional cycles or mutating cache state.
|
// without computing additional cycles or mutating cache state.
|
||||||
_currentMontgomery = _currentMontgomery.MontgomeryMultiply(montgomeryDelta, _modulus, _nPrime);
|
_currentMontgomery = _currentMontgomery.MontgomeryMultiplyCpu(montgomeryDelta, _modulus, _nPrime);
|
||||||
PreviousExponent = exponent;
|
PreviousExponent = exponent;
|
||||||
isUnity = _currentMontgomery == _montgomeryOne;
|
isUnity = _currentMontgomery == _montgomeryOne;
|
||||||
return true;
|
return true;
|
||||||
@@ -138,5 +138,5 @@ internal struct ExponentRemainderStepperCpu
|
|||||||
PreviousExponent = exponent;
|
PreviousExponent = exponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ulong ReduceCurrent() => _currentMontgomery.MontgomeryMultiply(1UL, _modulus, _nPrime);
|
private ulong ReduceCurrent() => _currentMontgomery.MontgomeryMultiplyCpu(1UL, _modulus, _nPrime);
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ public readonly struct MontgomeryDivisorData(ulong modulus, ulong nPrime, ulong
|
|||||||
ulong nPrime = ComputeMontgomeryNPrime(modulus);
|
ulong nPrime = ComputeMontgomeryNPrime(modulus);
|
||||||
ulong montgomeryOne = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64, modulus);
|
ulong montgomeryOne = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64, modulus);
|
||||||
ulong montgomeryTwo = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64x2, modulus);
|
ulong montgomeryTwo = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64x2, modulus);
|
||||||
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiply(montgomeryTwo, montgomeryTwo, modulus, nPrime);
|
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiplyCpu(montgomeryTwo, montgomeryTwo, modulus, nPrime);
|
||||||
|
|
||||||
return new MontgomeryDivisorData(
|
return new MontgomeryDivisorData(
|
||||||
modulus,
|
modulus,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public static partial class ULongExtensions
|
|||||||
{
|
{
|
||||||
if (((exponent >> index) & 1UL) == 0UL)
|
if (((exponent >> index) & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(result, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(result, modulus, nPrime);
|
||||||
index--;
|
index--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -59,14 +59,14 @@ public static partial class ULongExtensions
|
|||||||
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.MontgomeryMultiplyCpu(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.MontgomeryMultiplyCpu(multiplier, modulus, nPrime);
|
||||||
|
|
||||||
index = windowStart - 1;
|
index = windowStart - 1;
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ public static partial class ULongExtensions
|
|||||||
|
|
||||||
if (!keepMontgomery)
|
if (!keepMontgomery)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(1UL, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -96,7 +96,7 @@ public static partial class ULongExtensions
|
|||||||
for (int i = 1; i < oddPowers.Length; i++)
|
for (int i = 1; i < oddPowers.Length; i++)
|
||||||
{
|
{
|
||||||
previous = oddPowers[i - 1];
|
previous = oddPowers[i - 1];
|
||||||
oddPowers[i] = previous.MontgomeryMultiply(square, modulus, nPrime);
|
oddPowers[i] = previous.MontgomeryMultiplyCpu(square, modulus, nPrime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,17 +49,40 @@ public static partial class ULongExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static ulong MontgomeryMultiplyGpu(this ulong a, ulong b, ulong modulus, ulong nPrime)
|
internal static ulong MontgomeryMultiplyGpu(this ulong a, ulong b, ulong modulus, ulong nPrime)
|
||||||
{
|
{
|
||||||
ulong tLow = unchecked(a * b);
|
// Mirror the struct-based MontMul64 helper measured as the second-fastest GPU-compatible
|
||||||
ulong m = unchecked(tLow * nPrime);
|
// option in GpuUInt128Montgomery64Benchmarks so accelerator kernels reuse the validated path.
|
||||||
ulong mTimesModulusLow = unchecked(m * modulus);
|
MultiplyPartsGpu(a, b, out ulong productHigh, out ulong productLow);
|
||||||
|
MultiplyPartsGpu(productLow, nPrime, out _, out ulong mLow);
|
||||||
|
MultiplyPartsGpu(mLow, modulus, out ulong mTimesModulusHigh, out ulong mTimesModulusLow);
|
||||||
|
|
||||||
ulong result = unchecked(a.MulHighGpu(b) + m.MulHighGpu(modulus) + (unchecked(tLow + mTimesModulusLow) < tLow ? 1UL : 0UL));
|
ulong sumLow = unchecked(productLow + mTimesModulusLow);
|
||||||
if (result >= modulus)
|
ulong carry = sumLow < productLow ? 1UL : 0UL;
|
||||||
|
ulong sumHigh = unchecked(productHigh + mTimesModulusHigh + carry);
|
||||||
|
|
||||||
|
if (sumHigh >= modulus)
|
||||||
{
|
{
|
||||||
result -= modulus;
|
sumHigh -= modulus;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return sumHigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void MultiplyPartsGpu(ulong left, ulong right, out ulong high, out ulong low)
|
||||||
|
{
|
||||||
|
ulong leftLow = (uint)left;
|
||||||
|
ulong leftHigh = left >> 32;
|
||||||
|
ulong rightLow = (uint)right;
|
||||||
|
ulong rightHigh = right >> 32;
|
||||||
|
|
||||||
|
ulong lowProduct = unchecked(leftLow * rightLow);
|
||||||
|
ulong cross1 = unchecked(leftHigh * rightLow);
|
||||||
|
ulong cross2 = unchecked(leftLow * rightHigh);
|
||||||
|
ulong highProduct = unchecked(leftHigh * rightHigh);
|
||||||
|
|
||||||
|
ulong carry = unchecked((lowProduct >> 32) + (uint)cross1 + (uint)cross2);
|
||||||
|
low = unchecked((lowProduct & 0xFFFFFFFFUL) | (carry << 32));
|
||||||
|
high = unchecked(highProduct + (cross1 >> 32) + (cross2 >> 32) + (carry >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|||||||
@@ -553,7 +553,7 @@ public static partial class ULongExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong MontgomeryMultiply(this ulong a, ulong b, ulong modulus, ulong nPrime)
|
public static ulong MontgomeryMultiplyCpu(this ulong a, ulong b, ulong modulus, ulong nPrime)
|
||||||
{
|
{
|
||||||
ulong tLow = unchecked(a * b);
|
ulong tLow = unchecked(a * b);
|
||||||
ulong m = unchecked(tLow * nPrime);
|
ulong m = unchecked(tLow * nPrime);
|
||||||
@@ -581,7 +581,7 @@ public static partial class ULongExtensions
|
|||||||
{
|
{
|
||||||
if ((remainingExponent & 1UL) != 0UL)
|
if ((remainingExponent & 1UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = result.MontgomeryMultiply(baseVal, modulus, nPrime);
|
result = result.MontgomeryMultiplyCpu(baseVal, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingExponent >>= 1;
|
remainingExponent >>= 1;
|
||||||
@@ -590,10 +590,10 @@ public static partial class ULongExtensions
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVal = baseVal.MontgomeryMultiply(baseVal, modulus, nPrime);
|
baseVal = baseVal.MontgomeryMultiplyCpu(baseVal, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return keepMontgomery ? result : result.MontgomeryMultiply(1UL, modulus, nPrime);
|
return keepMontgomery ? result : result.MontgomeryMultiplyCpu(1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user