Fix GPU residue tester iteration and add regression tests

This commit is contained in:
Marek Lemańczyk committed 2025-09-21 00:14:33 +02:00
1 parent 4650faed58
commit f9b4f912e2
2 files changed
+84 -3

No files matched your search

@@ -3,6 +3,7 @@ using System.Linq;
using System.Reflection;
using FluentAssertions;
using PerfectNumbers.Core;
using PerfectNumbers.Core.Cpu;
using PerfectNumbers.Core.Gpu;
using Xunit;
using UInt128 = System.UInt128;
@@ -29,6 +30,54 @@ public class MersenneNumberResidueGpuTesterTests
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]
[Trait("Category", "Fast")]
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]
[InlineData(false)]
[InlineData(true)]
@@ -59,9 +59,9 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
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);
if (setStart >= limitInclusive)
{
@@ -113,7 +113,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
}
}
kStart = checked(kStart + batchSize128);
kStart = checked(kStart + (UInt128)currentSize);
}
}
}