From 86192a71b089ba20bf28e8c1fb06df8c381439d5 Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Wed, 3 Dec 2025 00:57:25 +0100 Subject: [PATCH] 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. --- ...rsenneNumberDivisorByDivisorTesterTests.cs | 2 +- .../MersenneNumberDivisorCpuTesterTests.cs | 26 +++--- .../MersenneNumberDivisorGpuTesterTests.cs | 44 ++++----- .../Cpu/MersenneCpuDivisorScanSession.cs | 44 +++++---- ...MersenneNumberDivisorByDivisorCpuTester.cs | 93 ++++++++++++++++++- ...MersenneNumberDivisorByDivisorGpuTester.cs | 9 +- .../IMersenneNumberDivisorByDivisorTester.cs | 2 +- 7 files changed, 158 insertions(+), 62 deletions(-) diff --git a/PerfectNumbers.Core.Tests/MersenneNumberDivisorByDivisorTesterTests.cs b/PerfectNumbers.Core.Tests/MersenneNumberDivisorByDivisorTesterTests.cs index 2749c3a..3f28334 100644 --- a/PerfectNumbers.Core.Tests/MersenneNumberDivisorByDivisorTesterTests.cs +++ b/PerfectNumbers.Core.Tests/MersenneNumberDivisorByDivisorTesterTests.cs @@ -104,7 +104,7 @@ public class MersenneNumberDivisorByDivisorTesterTests private sealed class DummySession : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession { - public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan primes, Span hits) + public bool CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan primes) { throw new NotSupportedException(); } diff --git a/PerfectNumbers.Core.Tests/MersenneNumberDivisorCpuTesterTests.cs b/PerfectNumbers.Core.Tests/MersenneNumberDivisorCpuTesterTests.cs index c5a127a..dddebee 100644 --- a/PerfectNumbers.Core.Tests/MersenneNumberDivisorCpuTesterTests.cs +++ b/PerfectNumbers.Core.Tests/MersenneNumberDivisorCpuTesterTests.cs @@ -47,16 +47,18 @@ public class MersenneNumberDivisorCpuTesterTests try { ulong[] primes = [5UL, 7UL, 11UL, 13UL]; - byte[] hits = new byte[primes.Length]; ulong cycle23 = MersenneDivisorCycles.CalculateCycleLengthCpu(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL)); - session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primes, hits); - hits.Should().ContainInOrder([0, 0, 1, 0]); + session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primes).Should().BeTrue(); + + 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)); - session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primes, hits); - hits.Should().ContainInOrder([1, 0, 0, 0]); + session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primes).Should().BeTrue(); + + ulong[] primesBeforeHit = [7UL, 11UL, 13UL]; + session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primesBeforeHit).Should().BeFalse(); } finally { @@ -77,13 +79,13 @@ public class MersenneNumberDivisorCpuTesterTests try { ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL]; - byte[] hits = new byte[exponents.Length]; MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL); 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 { @@ -104,13 +106,13 @@ public class MersenneNumberDivisorCpuTesterTests try { ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL]; - byte[] hits = new byte[exponents.Length]; MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL); 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 { diff --git a/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs b/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs index b8f1bd4..2248e5f 100644 --- a/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs +++ b/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs @@ -229,11 +229,11 @@ public class MersenneNumberDivisorGpuTesterTests try { 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 { @@ -254,16 +254,18 @@ public class MersenneNumberDivisorGpuTesterTests try { ulong[] primes = [31UL, 37UL, 41UL, 43UL]; - byte[] hits = new byte[primes.Length]; ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL)); - session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits); - hits.Should().ContainInOrder([0, 1, 0, 0]); + session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes).Should().BeTrue(); + + 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)); - session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primes, hits); - hits.Should().ContainInOrder([0, 0, 1, 0]); + session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primes).Should().BeTrue(); + + ulong[] primesWithoutMatchingExponent = [31UL, 37UL, 43UL]; + session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primesWithoutMatchingExponent).Should().BeFalse(); } finally { @@ -288,12 +290,12 @@ public class MersenneNumberDivisorGpuTesterTests try { ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL]; - byte[] hits = new byte[primes.Length]; 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 { @@ -317,14 +319,14 @@ public class MersenneNumberDivisorGpuTesterTests try { ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL]; - byte[] hits = new byte[exponents.Length]; MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL); 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 { @@ -348,14 +350,14 @@ public class MersenneNumberDivisorGpuTesterTests try { ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL]; - byte[] hits = new byte[exponents.Length]; MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL); 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 { @@ -424,12 +426,12 @@ public class MersenneNumberDivisorGpuTesterTests try { ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL]; - byte[] hits = new byte[primes.Length]; 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 { diff --git a/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs b/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs index eac7187..85db934 100644 --- a/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs +++ b/PerfectNumbers.Core/Cpu/MersenneCpuDivisorScanSession.cs @@ -21,35 +21,36 @@ internal sealed class MersenneCpuDivisorScanSession(PrimeOrderCalculatorAccelera }; } - public void CheckDivisor( + public bool CheckDivisor( ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, - in ReadOnlySpan primes, - Span hits) + in ReadOnlySpan primes) { int length = primes.Length; // EvenPerfectBitScanner always provides at least one exponent on this path. // Keep the guard commented out for tests that might reuse the session differently. // if (length == 0) // { - // return; + // return false; // } - if (divisorData.Modulus != divisor) - { - throw new InvalidOperationException("Divisor data is for a different modulus"); - // cachedData = MontgomeryDivisorData.FromModulus(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); + // } if (divisorCycle == 0UL) { divisorCycle = _getCycleLength(divisor); - if (divisorCycle == 0UL) - { - // DivisorCycleCache guarantees a positive cycle for divisors greater than one. - throw new InvalidOperationException($"Divisor cycle solver returned zero for divisor {divisor}."); - } + // 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}."); + // } } // Keep these remainder steppers in place so future updates continue reusing the previously computed residues. @@ -60,21 +61,26 @@ internal sealed class MersenneCpuDivisorScanSession(PrimeOrderCalculatorAccelera bool initialUnity = exponentStepper.InitializeCpuIsUnity(primes[0]); ulong remainder = cycleStepper.Initialize(primes[0]); - hits[0] = remainder == 0UL - ? (initialUnity ? (byte)1 : (byte)0) - : (byte)0; + if (remainder == 0UL && initialUnity) + { + return true; + } for (int i = 1; i < length; i++) { remainder = cycleStepper.ComputeNext(primes[i]); if (remainder != 0UL) { - hits[i] = 0; continue; } - hits[i] = exponentStepper.ComputeNextIsUnity(primes[i]) ? (byte)1 : (byte)0; + if (exponentStepper.ComputeNextIsUnity(primes[i])) + { + return true; + } } + + return false; } public void Return() diff --git a/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs b/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs index dc068ec..b693b10 100644 --- a/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs +++ b/PerfectNumbers.Core/Cpu/MersenneNumberDivisorByDivisorCpuTester.cs @@ -231,12 +231,18 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv byte step3; byte step7; byte step11; + byte step13; + byte step17; + byte step19; byte remainder10; byte remainder8; byte remainder3; byte remainder7; byte remainder11; + byte remainder13; + byte remainder17; + byte remainder19; if (stepHigh == 0UL && limitHigh == 0UL) { @@ -245,6 +251,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv step3 = (byte)(stepLow % 3UL); step7 = (byte)(stepLow % 7UL); step11 = (byte)(stepLow % 11UL); + step13 = (byte)(stepLow % 13UL); + step17 = (byte)(stepLow % 17UL); + step19 = (byte)(stepLow % 19UL); ulong maxK = allowedMax > 0UL ? (allowedMax - 1UL) / stepLow : 0UL; if (maxK == 0UL) @@ -274,6 +283,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv step3, step7, step11, + step13, + step17, + step19, ref currentK, out processedTop, out foundDivisor); @@ -302,6 +314,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv step3, step7, step11, + step13, + step17, + step19, ref currentK, out processedBottom, out foundDivisor); @@ -317,17 +332,23 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv step3 = (byte)(((stepHigh % 3UL) + (stepLow % 3UL)) % 3UL); step7 = (byte)((((stepHigh % 7UL) * 2UL) + (stepLow % 7UL)) % 7UL); 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); remainder8 = (byte)(divisorLow % 8UL); remainder3 = (byte)(((divisorHigh % 3UL) + (divisorLow % 3UL)) % 3UL); remainder7 = (byte)((((divisorHigh % 7UL) * 2UL) + (divisorLow % 7UL)) % 7UL); 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; 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) { ulong candidate = divisor.Low; @@ -379,6 +400,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv remainder3 = AddMod3(remainder3, step3); remainder7 = AddMod7(remainder7, step7); remainder11 = AddMod11(remainder11, step11); + remainder13 = AddMod13(remainder13, step13); + remainder17 = AddMod17(remainder17, step17); + remainder19 = AddMod19(remainder19, step19); } processedAll = true; @@ -399,6 +423,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv byte step3, byte step7, byte step11, + byte step13, + byte step17, + byte step19, ref ulong currentK, out bool processedAll, out ulong foundDivisor) @@ -435,6 +462,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv byte remainder3 = (byte)(startDivisor % 3UL); byte remainder7 = (byte)(startDivisor % 7UL); byte remainder11 = (byte)(startDivisor % 11UL); + byte remainder13 = (byte)(startDivisor % 13UL); + byte remainder17 = (byte)(startDivisor % 17UL); + byte remainder19 = (byte)(startDivisor % 19UL); return CheckDivisors64( gpu, @@ -448,11 +478,17 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv step3, step7, step11, + step13, + step17, + step19, remainder10, remainder8, remainder3, remainder7, remainder11, + remainder13, + remainder17, + remainder19, ref currentK, out processedAll, out foundDivisor); @@ -470,11 +506,17 @@ private bool CheckDivisors64( byte step3, byte step7, byte step11, + byte step13, + byte step17, + byte step19, byte remainder10, byte remainder8, byte remainder3, byte remainder7, byte remainder11, + byte remainder13, + byte remainder17, + byte remainder19, ref ulong currentK, out bool processedAll, out ulong foundDivisor) @@ -485,7 +527,7 @@ private bool CheckDivisors64( { 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); ulong divisorCycle; @@ -539,7 +581,7 @@ private bool CheckDivisors64( ulong remainingIterations = ((limit - divisor) / step) + 1UL; 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) { MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor); @@ -593,6 +635,9 @@ private bool CheckDivisors64( remainder3 = AddMod3(remainder3, step3); remainder7 = AddMod7(remainder7, step7); 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; } + [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)] private static byte AddMod10(byte value, byte delta) { diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs index 557fd11..acf086b 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs @@ -717,13 +717,13 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN } } - public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan primes, Span hits) + public bool CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan primes) { int length = primes.Length; // EvenPerfectBitScanner always supplies at least one exponent per divisor check, so the guard stays commented out. // if (length == 0) // { - // return; + // return false; // } // 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); - Span hitSlice = hits.Slice(0, length); - ref byte hitRef = ref MemoryMarshal.GetReference(hitSlice); - hitView.CopyToCPU(stream, ref hitRef, length); + firstHitView.CopyToCPU(stream, ref sentinel, 1); stream.Synchronize(); // Monitor.Exit(_lease.ExecutionLock); + return sentinel == 0; } public void Return() diff --git a/PerfectNumbers.Core/IMersenneNumberDivisorByDivisorTester.cs b/PerfectNumbers.Core/IMersenneNumberDivisorByDivisorTester.cs index d5437ff..942864b 100644 --- a/PerfectNumbers.Core/IMersenneNumberDivisorByDivisorTester.cs +++ b/PerfectNumbers.Core/IMersenneNumberDivisorByDivisorTester.cs @@ -28,7 +28,7 @@ public interface IMersenneNumberDivisorByDivisorTester public interface IDivisorScanSession { - void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan primes, Span hits); + bool CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan primes); void Return(); }