Optimizations. More TODOs added.
This commit is contained in:
1 parent
58a4473dde
commit
2484d506d6
1 file changed
+33
-45
@@ -264,23 +264,23 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
return _divisorLimit;
|
return _divisorLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong maxByPrime = (1UL << (int)(prime - 1UL)) - 1UL;
|
return Math.Min((1UL << (int)(prime - 1UL)) - 1UL, _divisorLimit);
|
||||||
return Math.Min(maxByPrime, _divisorLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckKernel(Index1D index, ulong prime, ArrayView<MontgomeryDivisorData> divisors, ArrayView<byte> hits)
|
private static void CheckKernel(Index1D index, ulong prime, ArrayView<MontgomeryDivisorData> divisors, ArrayView<byte> hits)
|
||||||
{
|
{
|
||||||
MontgomeryDivisorData divisor = divisors[index];
|
MontgomeryDivisorData divisor = divisors[index];
|
||||||
if (divisor.Modulus <= 1UL || (divisor.Modulus & 1UL) == 0UL)
|
ulong modulus = divisor.Modulus;
|
||||||
|
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
hits[index] = 0;
|
hits[index] = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong pow = Pow2Mod(prime, divisor);
|
hits[index] = Pow2Mod(prime, divisor) == 1UL ? (byte)1 : (byte)0;
|
||||||
hits[index] = pow == 1UL ? (byte)1 : (byte)0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Let's create a pool for these and let's rent them and return, when not needed
|
||||||
public sealed class DivisorScanSession : IDisposable
|
public sealed class DivisorScanSession : IDisposable
|
||||||
{
|
{
|
||||||
private readonly MersenneNumberDivisorByDivisorGpuTester _owner;
|
private readonly MersenneNumberDivisorByDivisorGpuTester _owner;
|
||||||
@@ -329,7 +329,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<byte>> kernel = _kernel;
|
Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<byte>> kernel = _kernel;
|
||||||
ArrayView1D<ulong, Stride1D.Dense> primesView;
|
ArrayView1D<ulong, Stride1D.Dense> primesView;
|
||||||
ArrayView1D<byte, Stride1D.Dense> hitsView;
|
ArrayView1D<byte, Stride1D.Dense> hitsView;
|
||||||
MersenneDivisorCycles? divisorCycles = useCycles ? MersenneDivisorCycles.Shared : null;
|
MersenneDivisorCycles? divisorCycles = MersenneDivisorCycles.Shared;
|
||||||
ulong cycle = useCycles ? divisorCycles!.GetCycle(divisor) : 0UL, primeValue;
|
ulong cycle = useCycles ? divisorCycles!.GetCycle(divisor) : 0UL, primeValue;
|
||||||
MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor);
|
MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor);
|
||||||
Span<ulong> primeSpan = [];
|
Span<ulong> primeSpan = [];
|
||||||
@@ -420,7 +420,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong Pow2Mod(ulong exponent, MontgomeryDivisorData divisor)
|
private static ulong Pow2Mod(ulong exponent, in MontgomeryDivisorData divisor)
|
||||||
{
|
{
|
||||||
ulong modulus = divisor.Modulus;
|
ulong modulus = divisor.Modulus;
|
||||||
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
||||||
@@ -430,24 +430,24 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
|
|
||||||
ulong result = divisor.MontgomeryOne;
|
ulong result = divisor.MontgomeryOne;
|
||||||
ulong baseVal = divisor.MontgomeryTwo;
|
ulong baseVal = divisor.MontgomeryTwo;
|
||||||
ulong exp = exponent;
|
ulong nPrime = divisor.NPrime;
|
||||||
while (exp > 0UL)
|
while (exponent > 0UL)
|
||||||
{
|
{
|
||||||
if ((exp & 1UL) != 0UL)
|
if ((exponent & 1UL) != 0UL)
|
||||||
{
|
{
|
||||||
result = MontgomeryMultiply(result, baseVal, modulus, divisor.NPrime);
|
result = MontgomeryMultiply(result, baseVal, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
exp >>= 1;
|
exponent >>= 1;
|
||||||
if (exp == 0UL)
|
if (exponent == 0UL)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVal = MontgomeryMultiply(baseVal, baseVal, modulus, divisor.NPrime);
|
baseVal = MontgomeryMultiply(baseVal, baseVal, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MontgomeryMultiply(result, 1UL, modulus, divisor.NPrime);
|
return MontgomeryMultiply(result, 1UL, modulus, nPrime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -455,51 +455,45 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
{
|
{
|
||||||
ulong tLow = unchecked(a * b);
|
ulong tLow = unchecked(a * b);
|
||||||
ulong m = unchecked(tLow * nPrime);
|
ulong m = unchecked(tLow * nPrime);
|
||||||
ulong sumLow = unchecked(tLow + m * modulus);
|
|
||||||
ulong carry = sumLow < tLow ? 1UL : 0UL;
|
|
||||||
ulong sumHigh = unchecked(MultiplyHigh(a, b) + MultiplyHigh(m, modulus) + carry);
|
|
||||||
|
|
||||||
ulong result = sumHigh;
|
// We're reusing tLow variable as the result to perform just a little bit better
|
||||||
if (result >= modulus)
|
tLow = unchecked(MultiplyHigh(a, b) + MultiplyHigh(m, modulus) + (unchecked(tLow + m * modulus) < tLow ? 1UL : 0UL));
|
||||||
|
if (tLow >= modulus)
|
||||||
{
|
{
|
||||||
result -= modulus;
|
tLow -= modulus;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return tLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckKernelByPrime(Index1D index, MontgomeryDivisorData divisor, ArrayView<ulong> primes, ArrayView<byte> hits)
|
private static void CheckKernelByPrime(Index1D index, MontgomeryDivisorData divisor, ArrayView<ulong> primes, ArrayView<byte> hits)
|
||||||
{
|
{
|
||||||
ulong prime = primes[index];
|
ulong modulus = divisor.Modulus;
|
||||||
if (divisor.Modulus <= 1UL || (divisor.Modulus & 1UL) == 0UL)
|
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
hits[index] = 0;
|
hits[index] = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong pow = Pow2Mod(prime, divisor);
|
hits[index] = Pow2Mod(primes[index], divisor) == 1UL ? (byte)1 : (byte)0;
|
||||||
hits[index] = pow == 1UL ? (byte)1 : (byte)0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MontgomeryDivisorData CreateMontgomeryDivisorData(ulong modulus)
|
private static MontgomeryDivisorData CreateMontgomeryDivisorData(ulong modulus)
|
||||||
{
|
{
|
||||||
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
return new MontgomeryDivisorData(modulus, 0UL, 0UL, 0UL);
|
return new(modulus, 0UL, 0UL, 0UL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong nPrime = ComputeMontgomeryNPrime(modulus);
|
return new(
|
||||||
ulong montgomeryOne = ComputeMontgomeryResidue(1UL, modulus);
|
modulus,
|
||||||
ulong montgomeryTwo = ComputeMontgomeryResidue(2UL, modulus);
|
ComputeMontgomeryNPrime(modulus),
|
||||||
return new MontgomeryDivisorData(modulus, nPrime, montgomeryOne, montgomeryTwo);
|
ComputeMontgomeryResidue(1UL, modulus),
|
||||||
|
ComputeMontgomeryResidue(2UL, modulus)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong ComputeMontgomeryResidue(ulong value, ulong modulus)
|
private static ulong ComputeMontgomeryResidue(ulong value, ulong modulus) => (ulong)((UInt128)value * (UInt128.One << 64) % modulus);
|
||||||
{
|
|
||||||
UInt128 r = UInt128.One << 64;
|
|
||||||
UInt128 result = ((UInt128)value * r) % modulus;
|
|
||||||
return (ulong)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong ComputeMontgomeryNPrime(ulong modulus)
|
private static ulong ComputeMontgomeryNPrime(ulong modulus)
|
||||||
{
|
{
|
||||||
@@ -521,14 +515,8 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
ulong yLow = (uint)y;
|
ulong yLow = (uint)y;
|
||||||
ulong yHigh = y >> 32;
|
ulong yHigh = y >> 32;
|
||||||
|
|
||||||
ulong lowProduct = xLow * yLow;
|
ulong mid = xHigh * yLow + ((xLow * yLow) >> 32);
|
||||||
ulong mid = xHigh * yLow + (lowProduct >> 32);
|
return xHigh * yHigh + (mid >> 32) + (((mid & 0xFFFFFFFFUL) + xLow * yHigh) >> 32);
|
||||||
ulong midLow = mid & 0xFFFFFFFFUL;
|
|
||||||
ulong midHigh = mid >> 32;
|
|
||||||
midLow += xLow * yHigh;
|
|
||||||
|
|
||||||
ulong resultHigh = xHigh * yHigh + midHigh + (midLow >> 32);
|
|
||||||
return resultHigh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong DivisorLimit
|
public ulong DivisorLimit
|
||||||
|
|||||||
Reference in new issue
Block a user