Divisor checking optimized to only flag if divisor was found or not without returning complete array of hits. We'll now also track residues for 13, 17 & 19 as the most frequent ones.

This commit is contained in:
mlemanczyk committed 2025-12-03 00:57:25 +01:00
1 parent 85a90c70bf
commit 86192a71b0
7 files changed
+158 -62

No files matched your search

@@ -104,7 +104,7 @@ public class MersenneNumberDivisorByDivisorTesterTests
private sealed class DummySession : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession private sealed class DummySession : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession
{ {
public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes, Span<byte> hits) public bool CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
@@ -47,16 +47,18 @@ public class MersenneNumberDivisorCpuTesterTests
try try
{ {
ulong[] primes = [5UL, 7UL, 11UL, 13UL]; ulong[] primes = [5UL, 7UL, 11UL, 13UL];
byte[] hits = new byte[primes.Length];
ulong cycle23 = MersenneDivisorCycles.CalculateCycleLengthCpu(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL)); ulong cycle23 = MersenneDivisorCycles.CalculateCycleLengthCpu(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL));
session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primes, hits); session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primes).Should().BeTrue();
hits.Should().ContainInOrder([0, 0, 1, 0]);
ulong[] primesWithoutHit = [5UL, 7UL, 13UL];
session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primesWithoutHit).Should().BeFalse();
Array.Fill(hits, (byte)0);
ulong cycle31 = MersenneDivisorCycles.CalculateCycleLengthCpu(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL)); ulong cycle31 = MersenneDivisorCycles.CalculateCycleLengthCpu(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL));
session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primes, hits); session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primes).Should().BeTrue();
hits.Should().ContainInOrder([1, 0, 0, 0]);
ulong[] primesBeforeHit = [7UL, 11UL, 13UL];
session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primesBeforeHit).Should().BeFalse();
} }
finally finally
{ {
@@ -77,13 +79,13 @@ public class MersenneNumberDivisorCpuTesterTests
try try
{ {
ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL]; ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL];
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(7UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits); session.CheckDivisor(7UL, divisorData, cycle, exponents).Should().BeTrue();
hits.Should().Equal([1, 0, 1, 0, 1]); ulong[] nonDivisibleExponents = [5UL, 11UL];
session.CheckDivisor(7UL, divisorData, cycle, nonDivisibleExponents).Should().BeFalse();
} }
finally finally
{ {
@@ -104,13 +106,13 @@ public class MersenneNumberDivisorCpuTesterTests
try try
{ {
ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL]; ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL];
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(11UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits); session.CheckDivisor(11UL, divisorData, cycle, exponents).Should().BeTrue();
hits.Should().Equal([1, 0, 1, 0, 1]); ulong[] nonDivisibleExponents = [5UL, 17UL];
session.CheckDivisor(11UL, divisorData, cycle, nonDivisibleExponents).Should().BeFalse();
} }
finally finally
{ {
@@ -229,11 +229,11 @@ public class MersenneNumberDivisorGpuTesterTests
try try
{ {
ulong[] primes = [31UL, 37UL, 41UL]; ulong[] primes = [31UL, 37UL, 41UL];
byte[] hits = new byte[primes.Length];
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), 0UL, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), 0UL, primes).Should().BeTrue();
hits.Should().ContainInOrder([0, 1, 0]); ulong[] primesWithoutHit = [31UL, 41UL];
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), 0UL, primesWithoutHit).Should().BeFalse();
} }
finally finally
{ {
@@ -254,16 +254,18 @@ public class MersenneNumberDivisorGpuTesterTests
try try
{ {
ulong[] primes = [31UL, 37UL, 41UL, 43UL]; ulong[] primes = [31UL, 37UL, 41UL, 43UL];
byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL)); ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes).Should().BeTrue();
hits.Should().ContainInOrder([0, 1, 0, 0]);
ulong[] primesBeforeHit = [31UL];
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primesBeforeHit).Should().BeFalse();
Array.Fill(hits, (byte)0);
ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL)); ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL));
session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primes, hits); session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primes).Should().BeTrue();
hits.Should().ContainInOrder([0, 0, 1, 0]);
ulong[] primesWithoutMatchingExponent = [31UL, 37UL, 43UL];
session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primesWithoutMatchingExponent).Should().BeFalse();
} }
finally finally
{ {
@@ -288,12 +290,12 @@ public class MersenneNumberDivisorGpuTesterTests
try try
{ {
ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL]; ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL];
byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL)); ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes).Should().BeTrue();
hits.Should().ContainInOrder([0, 1, 0, 0, 0]); ulong[] primesBeforeHit = [31UL];
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primesBeforeHit).Should().BeFalse();
} }
finally finally
{ {
@@ -317,14 +319,14 @@ public class MersenneNumberDivisorGpuTesterTests
try try
{ {
ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL]; ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL];
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 7UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits); session.CheckDivisor(7UL, divisorData, cycle, exponents).Should().BeTrue();
hits.Should().Equal([1, 0, 1, 0, 1]); ulong[] nonDivisibleExponents = [5UL, 11UL];
session.CheckDivisor(7UL, divisorData, cycle, nonDivisibleExponents).Should().BeFalse();
} }
finally finally
{ {
@@ -348,14 +350,14 @@ public class MersenneNumberDivisorGpuTesterTests
try try
{ {
ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL]; ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL];
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 11UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits); session.CheckDivisor(11UL, divisorData, cycle, exponents).Should().BeTrue();
hits.Should().Equal([1, 0, 1, 0, 1]); ulong[] nonDivisibleExponents = [5UL, 17UL];
session.CheckDivisor(11UL, divisorData, cycle, nonDivisibleExponents).Should().BeFalse();
} }
finally finally
{ {
@@ -424,12 +426,12 @@ public class MersenneNumberDivisorGpuTesterTests
try try
{ {
ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL]; ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL];
byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL)); ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes).Should().BeTrue();
hits.Should().ContainInOrder([0, 1, 0, 0, 0]); ulong[] primesBeforeHit = [31UL];
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primesBeforeHit).Should().BeFalse();
} }
finally finally
{ {
@@ -21,35 +21,36 @@ internal sealed class MersenneCpuDivisorScanSession(PrimeOrderCalculatorAccelera
}; };
} }
public void CheckDivisor( public bool CheckDivisor(
ulong divisor, ulong divisor,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
ulong divisorCycle, ulong divisorCycle,
in ReadOnlySpan<ulong> primes, in ReadOnlySpan<ulong> primes)
Span<byte> hits)
{ {
int length = primes.Length; int length = primes.Length;
// EvenPerfectBitScanner always provides at least one exponent on this path. // EvenPerfectBitScanner always provides at least one exponent on this path.
// Keep the guard commented out for tests that might reuse the session differently. // Keep the guard commented out for tests that might reuse the session differently.
// if (length == 0) // if (length == 0)
// { // {
// return; // return false;
// } // }
if (divisorData.Modulus != divisor) // This never kicks off in production code
{ // if (divisorData.Modulus != divisor)
throw new InvalidOperationException("Divisor data is for a different modulus"); // {
// cachedData = MontgomeryDivisorData.FromModulus(divisor); // throw new InvalidOperationException("Divisor data is for a different modulus");
} // // cachedData = MontgomeryDivisorData.FromModulus(divisor);
// }
if (divisorCycle == 0UL) if (divisorCycle == 0UL)
{ {
divisorCycle = _getCycleLength(divisor); divisorCycle = _getCycleLength(divisor);
if (divisorCycle == 0UL) // This never kicks off in production code
{ // if (divisorCycle == 0UL)
// DivisorCycleCache guarantees a positive cycle for divisors greater than one. // {
throw new InvalidOperationException($"Divisor cycle solver returned zero for divisor {divisor}."); // // DivisorCycleCache guarantees a positive cycle for divisors greater than one.
} // throw new InvalidOperationException($"Divisor cycle solver returned zero for divisor {divisor}.");
// }
} }
// Keep these remainder steppers in place so future updates continue reusing the previously computed residues. // Keep these remainder steppers in place so future updates continue reusing the previously computed residues.
@@ -60,23 +61,28 @@ internal sealed class MersenneCpuDivisorScanSession(PrimeOrderCalculatorAccelera
bool initialUnity = exponentStepper.InitializeCpuIsUnity(primes[0]); bool initialUnity = exponentStepper.InitializeCpuIsUnity(primes[0]);
ulong remainder = cycleStepper.Initialize(primes[0]); ulong remainder = cycleStepper.Initialize(primes[0]);
hits[0] = remainder == 0UL if (remainder == 0UL && initialUnity)
? (initialUnity ? (byte)1 : (byte)0) {
: (byte)0; return true;
}
for (int i = 1; i < length; i++) for (int i = 1; i < length; i++)
{ {
remainder = cycleStepper.ComputeNext(primes[i]); remainder = cycleStepper.ComputeNext(primes[i]);
if (remainder != 0UL) if (remainder != 0UL)
{ {
hits[i] = 0;
continue; continue;
} }
hits[i] = exponentStepper.ComputeNextIsUnity(primes[i]) ? (byte)1 : (byte)0; if (exponentStepper.ComputeNextIsUnity(primes[i]))
{
return true;
} }
} }
return false;
}
public void Return() public void Return()
{ {
ThreadStaticPools.ReturnMersenneCpuDivisorSession(this); ThreadStaticPools.ReturnMersenneCpuDivisorSession(this);
@@ -231,12 +231,18 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
byte step3; byte step3;
byte step7; byte step7;
byte step11; byte step11;
byte step13;
byte step17;
byte step19;
byte remainder10; byte remainder10;
byte remainder8; byte remainder8;
byte remainder3; byte remainder3;
byte remainder7; byte remainder7;
byte remainder11; byte remainder11;
byte remainder13;
byte remainder17;
byte remainder19;
if (stepHigh == 0UL && limitHigh == 0UL) if (stepHigh == 0UL && limitHigh == 0UL)
{ {
@@ -245,6 +251,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
step3 = (byte)(stepLow % 3UL); step3 = (byte)(stepLow % 3UL);
step7 = (byte)(stepLow % 7UL); step7 = (byte)(stepLow % 7UL);
step11 = (byte)(stepLow % 11UL); step11 = (byte)(stepLow % 11UL);
step13 = (byte)(stepLow % 13UL);
step17 = (byte)(stepLow % 17UL);
step19 = (byte)(stepLow % 19UL);
ulong maxK = allowedMax > 0UL ? (allowedMax - 1UL) / stepLow : 0UL; ulong maxK = allowedMax > 0UL ? (allowedMax - 1UL) / stepLow : 0UL;
if (maxK == 0UL) if (maxK == 0UL)
@@ -274,6 +283,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
step3, step3,
step7, step7,
step11, step11,
step13,
step17,
step19,
ref currentK, ref currentK,
out processedTop, out processedTop,
out foundDivisor); out foundDivisor);
@@ -302,6 +314,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
step3, step3,
step7, step7,
step11, step11,
step13,
step17,
step19,
ref currentK, ref currentK,
out processedBottom, out processedBottom,
out foundDivisor); out foundDivisor);
@@ -317,17 +332,23 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
step3 = (byte)(((stepHigh % 3UL) + (stepLow % 3UL)) % 3UL); step3 = (byte)(((stepHigh % 3UL) + (stepLow % 3UL)) % 3UL);
step7 = (byte)((((stepHigh % 7UL) * 2UL) + (stepLow % 7UL)) % 7UL); step7 = (byte)((((stepHigh % 7UL) * 2UL) + (stepLow % 7UL)) % 7UL);
step11 = (byte)((((stepHigh % 11UL) * 5UL) + (stepLow % 11UL)) % 11UL); step11 = (byte)((((stepHigh % 11UL) * 5UL) + (stepLow % 11UL)) % 11UL);
step13 = (byte)((((stepHigh % 13UL) * 3UL) + (stepLow % 13UL)) % 13UL);
step17 = (byte)(((stepHigh % 17UL) + (stepLow % 17UL)) % 17UL);
step19 = (byte)((((stepHigh % 19UL) * 17UL) + (stepLow % 19UL)) % 19UL);
remainder10 = (byte)((((divisorHigh % 10UL) * 6UL) + (divisorLow % 10UL)) % 10UL); remainder10 = (byte)((((divisorHigh % 10UL) * 6UL) + (divisorLow % 10UL)) % 10UL);
remainder8 = (byte)(divisorLow % 8UL); remainder8 = (byte)(divisorLow % 8UL);
remainder3 = (byte)(((divisorHigh % 3UL) + (divisorLow % 3UL)) % 3UL); remainder3 = (byte)(((divisorHigh % 3UL) + (divisorLow % 3UL)) % 3UL);
remainder7 = (byte)((((divisorHigh % 7UL) * 2UL) + (divisorLow % 7UL)) % 7UL); remainder7 = (byte)((((divisorHigh % 7UL) * 2UL) + (divisorLow % 7UL)) % 7UL);
remainder11 = (byte)((((divisorHigh % 11UL) * 5UL) + (divisorLow % 11UL)) % 11UL); remainder11 = (byte)((((divisorHigh % 11UL) * 5UL) + (divisorLow % 11UL)) % 11UL);
remainder13 = (byte)((((divisorHigh % 13UL) * 3UL) + (divisorLow % 13UL)) % 13UL);
remainder17 = (byte)(((divisorHigh % 17UL) + (divisorLow % 17UL)) % 17UL);
remainder19 = (byte)((((divisorHigh % 19UL) * 17UL) + (divisorLow % 19UL)) % 19UL);
var divisorPool = MontgomeryDivisorDataPool.Shared; var divisorPool = MontgomeryDivisorDataPool.Shared;
while (divisor.CompareTo(limit) <= 0) while (divisor.CompareTo(limit) <= 0)
{ {
bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0; bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0 && remainder13 != 0 && remainder17 != 0 && remainder19 != 0;
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0) if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
{ {
ulong candidate = divisor.Low; ulong candidate = divisor.Low;
@@ -379,6 +400,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
remainder3 = AddMod3(remainder3, step3); remainder3 = AddMod3(remainder3, step3);
remainder7 = AddMod7(remainder7, step7); remainder7 = AddMod7(remainder7, step7);
remainder11 = AddMod11(remainder11, step11); remainder11 = AddMod11(remainder11, step11);
remainder13 = AddMod13(remainder13, step13);
remainder17 = AddMod17(remainder17, step17);
remainder19 = AddMod19(remainder19, step19);
} }
processedAll = true; processedAll = true;
@@ -399,6 +423,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
byte step3, byte step3,
byte step7, byte step7,
byte step11, byte step11,
byte step13,
byte step17,
byte step19,
ref ulong currentK, ref ulong currentK,
out bool processedAll, out bool processedAll,
out ulong foundDivisor) out ulong foundDivisor)
@@ -435,6 +462,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
byte remainder3 = (byte)(startDivisor % 3UL); byte remainder3 = (byte)(startDivisor % 3UL);
byte remainder7 = (byte)(startDivisor % 7UL); byte remainder7 = (byte)(startDivisor % 7UL);
byte remainder11 = (byte)(startDivisor % 11UL); byte remainder11 = (byte)(startDivisor % 11UL);
byte remainder13 = (byte)(startDivisor % 13UL);
byte remainder17 = (byte)(startDivisor % 17UL);
byte remainder19 = (byte)(startDivisor % 19UL);
return CheckDivisors64( return CheckDivisors64(
gpu, gpu,
@@ -448,11 +478,17 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
step3, step3,
step7, step7,
step11, step11,
step13,
step17,
step19,
remainder10, remainder10,
remainder8, remainder8,
remainder3, remainder3,
remainder7, remainder7,
remainder11, remainder11,
remainder13,
remainder17,
remainder19,
ref currentK, ref currentK,
out processedAll, out processedAll,
out foundDivisor); out foundDivisor);
@@ -470,11 +506,17 @@ private bool CheckDivisors64(
byte step3, byte step3,
byte step7, byte step7,
byte step11, byte step11,
byte step13,
byte step17,
byte step19,
byte remainder10, byte remainder10,
byte remainder8, byte remainder8,
byte remainder3, byte remainder3,
byte remainder7, byte remainder7,
byte remainder11, byte remainder11,
byte remainder13,
byte remainder17,
byte remainder19,
ref ulong currentK, ref ulong currentK,
out bool processedAll, out bool processedAll,
out ulong foundDivisor) out ulong foundDivisor)
@@ -485,7 +527,7 @@ private bool CheckDivisors64(
{ {
if (divisor <= limit) if (divisor <= limit)
{ {
if (remainder3 != 0 && remainder7 != 0 && remainder11 != 0 && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0) if (remainder3 != 0 && remainder7 != 0 && remainder11 != 0 && remainder13 != 0 && remainder17 != 0 && remainder19 != 0 && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
{ {
MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor); MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor);
ulong divisorCycle; ulong divisorCycle;
@@ -539,7 +581,7 @@ private bool CheckDivisors64(
ulong remainingIterations = ((limit - divisor) / step) + 1UL; ulong remainingIterations = ((limit - divisor) / step) + 1UL;
while (true) while (true)
{ {
bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0; bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0 && remainder13 != 0 && remainder17 != 0 && remainder19 != 0;
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0) if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
{ {
MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor); MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor);
@@ -593,6 +635,9 @@ private bool CheckDivisors64(
remainder3 = AddMod3(remainder3, step3); remainder3 = AddMod3(remainder3, step3);
remainder7 = AddMod7(remainder7, step7); remainder7 = AddMod7(remainder7, step7);
remainder11 = AddMod11(remainder11, step11); remainder11 = AddMod11(remainder11, step11);
remainder13 = AddMod13(remainder13, step13);
remainder17 = AddMod17(remainder17, step17);
remainder19 = AddMod19(remainder19, step19);
} }
} }
@@ -733,6 +778,48 @@ private bool CheckDivisors64(
return (byte)sum; return (byte)sum;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte AddMod13(byte value, byte delta)
{
const int Modulus = 13;
int sum = value + delta;
if (sum >= Modulus)
{
sum -= Modulus;
}
return (byte)sum;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte AddMod17(byte value, byte delta)
{
const int Modulus = 17;
int sum = value + delta;
if (sum >= Modulus)
{
sum -= Modulus;
}
return (byte)sum;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte AddMod19(byte value, byte delta)
{
const int Modulus = 19;
int sum = value + delta;
if (sum >= Modulus)
{
sum -= Modulus;
}
return (byte)sum;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte AddMod10(byte value, byte delta) private static byte AddMod10(byte value, byte delta)
{ {
@@ -717,13 +717,13 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
} }
} }
public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes, Span<byte> hits) public bool CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes)
{ {
int length = primes.Length; int length = primes.Length;
// EvenPerfectBitScanner always supplies at least one exponent per divisor check, so the guard stays commented out. // EvenPerfectBitScanner always supplies at least one exponent per divisor check, so the guard stays commented out.
// if (length == 0) // if (length == 0)
// { // {
// return; // return false;
// } // }
// The GPU divisor sessions only materialize odd moduli greater than one (q = 2kp + 1), // The GPU divisor sessions only materialize odd moduli greater than one (q = 2kp + 1),
@@ -792,12 +792,11 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
kernel(stream, new Index1D(1), divisorView, offsetView, countView, exponentView, cycleView, hitView, firstHitView); kernel(stream, new Index1D(1), divisorView, offsetView, countView, exponentView, cycleView, hitView, firstHitView);
Span<byte> hitSlice = hits.Slice(0, length); firstHitView.CopyToCPU(stream, ref sentinel, 1);
ref byte hitRef = ref MemoryMarshal.GetReference(hitSlice);
hitView.CopyToCPU(stream, ref hitRef, length);
stream.Synchronize(); stream.Synchronize();
// Monitor.Exit(_lease.ExecutionLock); // Monitor.Exit(_lease.ExecutionLock);
return sentinel == 0;
} }
public void Return() public void Return()
@@ -28,7 +28,7 @@ public interface IMersenneNumberDivisorByDivisorTester
public interface IDivisorScanSession public interface IDivisorScanSession
{ {
void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes, Span<byte> hits); bool CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes);
void Return(); void Return();
} }