Merge pull request #49 from mlemanczyk/codex/analyze-commit-for-evenperfectbitscanner-issue
Fix GPU residue tester iteration and add regression tests
This commit is contained in:
2 files changed
+84
-3
No files matched your search
@@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using PerfectNumbers.Core;
|
using PerfectNumbers.Core;
|
||||||
|
using PerfectNumbers.Core.Cpu;
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using UInt128 = System.UInt128;
|
using UInt128 = System.UInt128;
|
||||||
@@ -29,6 +30,54 @@ public class MersenneNumberResidueGpuTesterTests
|
|||||||
RunCase(tester, 127UL, 1_001UL, expectedPrime: true);
|
RunCase(tester, 127UL, 1_001UL, expectedPrime: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false)]
|
||||||
|
[InlineData(true)]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Gpu_residue_scan_matches_cpu_for_small_configurations(bool useGpuOrder)
|
||||||
|
{
|
||||||
|
var gpuTester = new MersenneNumberResidueGpuTester(useGpuOrder);
|
||||||
|
var cpuTester = new MersenneNumberResidueCpuTester();
|
||||||
|
|
||||||
|
var configurations = new (ulong Exponent, UInt128 PerSetLimit, UInt128 SetCount, UInt128 OverallLimit)[]
|
||||||
|
{
|
||||||
|
(31UL, 8UL, 6UL, 48UL),
|
||||||
|
(61UL, 9UL, 9UL, 81UL),
|
||||||
|
(89UL, 12UL, 8UL, 96UL),
|
||||||
|
(107UL, 16UL, 8UL, 128UL),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var (exponent, perSetLimit, setCount, overallLimit) in configurations)
|
||||||
|
{
|
||||||
|
bool gpuPrime = true;
|
||||||
|
bool gpuExhausted = false;
|
||||||
|
gpuTester.Scan(
|
||||||
|
exponent,
|
||||||
|
(UInt128)exponent << 1,
|
||||||
|
LastDigitIsSeven(exponent),
|
||||||
|
perSetLimit,
|
||||||
|
setCount,
|
||||||
|
overallLimit,
|
||||||
|
ref gpuPrime,
|
||||||
|
ref gpuExhausted);
|
||||||
|
|
||||||
|
bool cpuPrime = true;
|
||||||
|
bool cpuExhausted = false;
|
||||||
|
cpuTester.Scan(
|
||||||
|
exponent,
|
||||||
|
(UInt128)exponent << 1,
|
||||||
|
LastDigitIsSeven(exponent),
|
||||||
|
perSetLimit,
|
||||||
|
setCount,
|
||||||
|
overallLimit,
|
||||||
|
ref cpuPrime,
|
||||||
|
ref cpuExhausted);
|
||||||
|
|
||||||
|
gpuPrime.Should().Be(cpuPrime, $"GPU residue scan should match CPU for exponent {exponent}");
|
||||||
|
gpuExhausted.Should().Be(cpuExhausted, $"GPU residue scan should report identical exhaustion for exponent {exponent}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
public void Scan_residue_gpu_handles_inaccurate_small_cycle_entries()
|
public void Scan_residue_gpu_handles_inaccurate_small_cycle_entries()
|
||||||
@@ -89,6 +138,38 @@ public class MersenneNumberResidueGpuTesterTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false)]
|
||||||
|
[InlineData(true)]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Mersenne_tester_residue_gpu_handles_known_primes_with_many_sets(bool useGpuOrder)
|
||||||
|
{
|
||||||
|
var tester = new MersenneNumberTester(
|
||||||
|
useIncremental: true,
|
||||||
|
useOrderCache: false,
|
||||||
|
kernelType: GpuKernelType.Pow2Mod,
|
||||||
|
useModuloWorkaround: false,
|
||||||
|
useOrder: false,
|
||||||
|
useGpuLucas: false,
|
||||||
|
useGpuScan: true,
|
||||||
|
useGpuOrder: useGpuOrder,
|
||||||
|
useResidue: true,
|
||||||
|
maxK: (UInt128)2_400_000UL,
|
||||||
|
residueDivisorSets: (UInt128)512UL);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool isPrime = tester.IsMersennePrime(127UL, out bool divisorsExhausted);
|
||||||
|
|
||||||
|
isPrime.Should().BeTrue();
|
||||||
|
divisorsExhausted.Should().BeTrue();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
GpuContextPool.DisposeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(false)]
|
[InlineData(false)]
|
||||||
[InlineData(true)]
|
[InlineData(true)]
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
|
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (ulong setIndex = 0; setIndex < setCount && Volatile.Read(ref isPrime); setIndex++)
|
for (UInt128 setIndex = UInt128.Zero; setIndex < setCount && Volatile.Read(ref isPrime); setIndex++)
|
||||||
{
|
{
|
||||||
UInt128 setOffset = checked(perSetLimit * (UInt128)setIndex);
|
UInt128 setOffset = checked(perSetLimit * setIndex);
|
||||||
UInt128 setStart = checked(setOffset + UInt128.One);
|
UInt128 setStart = checked(setOffset + UInt128.One);
|
||||||
if (setStart >= limitInclusive)
|
if (setStart >= limitInclusive)
|
||||||
{
|
{
|
||||||
@@ -113,7 +113,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kStart = checked(kStart + batchSize128);
|
kStart = checked(kStart + (UInt128)currentSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user