Merge pull request #39 from mlemanczyk/codex/fix-evenperfectbitscanner-prime-detection
Fix GPU residue false positives for Mersenne primes
This commit is contained in:
3 files changed
+98
-10
No files matched your search
@@ -351,6 +351,46 @@ public class ProgramTests
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
useDivisorField.SetValue(null, false);
|
||||||
|
mersenneField.SetValue(null, null);
|
||||||
|
primeField.SetValue(null, null);
|
||||||
|
residueField.SetValue(null, null);
|
||||||
|
forceCpuProp!.SetValue(null, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Residue_mode_with_default_limits_accepts_large_known_primes()
|
||||||
|
{
|
||||||
|
var useDivisorField = typeof(Program).GetField("_useDivisor", BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||||
|
var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||||
|
var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||||
|
var residueField = typeof(Program).GetField("PResidue", BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||||
|
var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu");
|
||||||
|
|
||||||
|
useDivisorField.SetValue(null, false);
|
||||||
|
mersenneField.SetValue(null, new ThreadLocal<MersenneNumberTester>(() => new MersenneNumberTester(
|
||||||
|
useIncremental: true,
|
||||||
|
useResidue: true,
|
||||||
|
maxK: 5_000_000UL,
|
||||||
|
residueDivisorSets: PerfectNumberConstants.ExtraDivisorCycleSearchLimit), trackAllValues: true));
|
||||||
|
primeField.SetValue(null, new ThreadLocal<PrimeTester>(() => new PrimeTester(), trackAllValues: true));
|
||||||
|
residueField.SetValue(null, new ThreadLocal<ModResidueTracker>(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true));
|
||||||
|
forceCpuProp!.SetValue(null, false);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Program.IsEvenPerfectCandidate(107UL, 0UL, out bool searched, out bool detailed).Should().BeTrue();
|
||||||
|
searched.Should().BeTrue();
|
||||||
|
detailed.Should().BeTrue();
|
||||||
|
|
||||||
|
Program.IsEvenPerfectCandidate(127UL, 0UL, out searched, out detailed).Should().BeTrue();
|
||||||
|
searched.Should().BeTrue();
|
||||||
|
detailed.Should().BeTrue();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
useDivisorField.SetValue(null, false);
|
||||||
mersenneField.SetValue(null, null);
|
mersenneField.SetValue(null, null);
|
||||||
primeField.SetValue(null, null);
|
primeField.SetValue(null, null);
|
||||||
residueField.SetValue(null, null);
|
residueField.SetValue(null, null);
|
||||||
|
|||||||
@@ -21,9 +21,57 @@ public class MersenneNumberResidueGpuTesterTests
|
|||||||
RunCase(tester, 29UL, 37UL, expectedPrime: false);
|
RunCase(tester, 29UL, 37UL, expectedPrime: false);
|
||||||
RunCase(tester, 31UL, 1_000UL, expectedPrime: true);
|
RunCase(tester, 31UL, 1_000UL, expectedPrime: true);
|
||||||
RunCase(tester, 89UL, 1_001UL, expectedPrime: true);
|
RunCase(tester, 89UL, 1_001UL, expectedPrime: true);
|
||||||
|
RunCase(tester, 107UL, 1_001UL, expectedPrime: true);
|
||||||
RunCase(tester, 127UL, 1_001UL, expectedPrime: true);
|
RunCase(tester, 127UL, 1_001UL, expectedPrime: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false)]
|
||||||
|
[InlineData(true)]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Scan_handles_multiple_sets_without_false_positives(bool useGpuOrder)
|
||||||
|
{
|
||||||
|
var tester = new MersenneNumberResidueGpuTester(useGpuOrder);
|
||||||
|
|
||||||
|
bool isPrime = true;
|
||||||
|
bool exhausted = false;
|
||||||
|
UInt128 perSetLimit = 1_666_667UL;
|
||||||
|
UInt128 setCount = 3UL;
|
||||||
|
UInt128 overallLimit = 5_000_000UL;
|
||||||
|
|
||||||
|
tester.Scan(
|
||||||
|
127UL,
|
||||||
|
(UInt128)127UL << 1,
|
||||||
|
LastDigitIsSeven(127UL),
|
||||||
|
perSetLimit,
|
||||||
|
setCount,
|
||||||
|
overallLimit,
|
||||||
|
ref isPrime,
|
||||||
|
ref exhausted);
|
||||||
|
|
||||||
|
isPrime.Should().BeTrue();
|
||||||
|
exhausted.Should().BeTrue();
|
||||||
|
|
||||||
|
isPrime = true;
|
||||||
|
exhausted = false;
|
||||||
|
perSetLimit = 20_000_000UL;
|
||||||
|
setCount = 5UL;
|
||||||
|
overallLimit = 100_000_000UL;
|
||||||
|
|
||||||
|
tester.Scan(
|
||||||
|
107UL,
|
||||||
|
(UInt128)107UL << 1,
|
||||||
|
LastDigitIsSeven(107UL),
|
||||||
|
perSetLimit,
|
||||||
|
setCount,
|
||||||
|
overallLimit,
|
||||||
|
ref isPrime,
|
||||||
|
ref exhausted);
|
||||||
|
|
||||||
|
isPrime.Should().BeTrue();
|
||||||
|
exhausted.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
private static void RunCase(MersenneNumberResidueGpuTester tester, ulong exponent, ulong maxK, bool expectedPrime)
|
private static void RunCase(MersenneNumberResidueGpuTester tester, ulong exponent, ulong maxK, bool expectedPrime)
|
||||||
{
|
{
|
||||||
bool isPrime = true;
|
bool isPrime = true;
|
||||||
|
|||||||
@@ -195,12 +195,12 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
||||||
|
|
||||||
// Small-cycles in-kernel early rejection from device table
|
// Small-cycles in-kernel early rejection from device table
|
||||||
if (q.High == 0UL && q.Low <= (ulong)(smallCycles.Length - 1))
|
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
|
||||||
{
|
{
|
||||||
uint cyc = smallCycles[(int)q.Low];
|
uint cyc = smallCycles[(int)q.Low];
|
||||||
if (cyc != 0U && (exponent % cyc) == 0UL)
|
if (cyc != 0U && (exponent % cyc) != 0UL)
|
||||||
{
|
{
|
||||||
orders[index] = exponent;
|
orders[index] = 0UL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,12 +340,12 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
|
|
||||||
GpuUInt128 k = kStart + (GpuUInt128)idx;
|
GpuUInt128 k = kStart + (GpuUInt128)idx;
|
||||||
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
||||||
if (q.High == 0UL && q.Low <= (ulong)(smallCycles.Length - 1))
|
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
|
||||||
{
|
{
|
||||||
uint cyc = smallCycles[(int)q.Low];
|
uint cyc = smallCycles[(int)q.Low];
|
||||||
if (cyc != 0U && (exponent % cyc) == 0UL)
|
if (cyc != 0U && (exponent % cyc) != 0UL)
|
||||||
{
|
{
|
||||||
orders[index] = exponent;
|
orders[index] = 0UL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,10 +468,10 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
||||||
|
|
||||||
// Small-cycles in-kernel early rejection from device table
|
// Small-cycles in-kernel early rejection from device table
|
||||||
if (q.High == 0UL && q.Low <= (ulong)(smallCycles.Length - 1))
|
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
|
||||||
{
|
{
|
||||||
uint cyc = smallCycles[(int)q.Low];
|
uint cyc = smallCycles[(int)q.Low];
|
||||||
if (cyc != 0U && (exponent % (ulong)cyc) == 0UL)
|
if (cyc != 0U && (exponent % (ulong)cyc) != 0UL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -547,10 +547,10 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
GpuUInt128 k = kStart + (GpuUInt128)idx;
|
GpuUInt128 k = kStart + (GpuUInt128)idx;
|
||||||
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
GpuUInt128 q = twoP.Mul64(k) + GpuUInt128.One;
|
||||||
// Small-cycles in-kernel early rejection from device table
|
// Small-cycles in-kernel early rejection from device table
|
||||||
if (q.High == 0UL && q.Low <= (ulong)(smallCycles.Length - 1))
|
if (q.High == 0UL && q.Low < (ulong)smallCycles.Length)
|
||||||
{
|
{
|
||||||
uint cyc = smallCycles[(int)q.Low];
|
uint cyc = smallCycles[(int)q.Low];
|
||||||
if (cyc != 0U && (exponent % (ulong)cyc) == 0UL)
|
if (cyc != 0U && (exponent % (ulong)cyc) != 0UL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user