Files

91 lines
3.2 KiB
C#

using System.Reflection;
using FluentAssertions;
using PerfectNumbers.Core.Gpu;
using Xunit;
using UInt128 = System.UInt128;
namespace PerfectNumbers.Core.Tests;
public class MersenneNumberOrderGpuTesterTests
{
private static LastDigit GetLastDigit(ulong exponent) => (exponent & 3UL) == 3UL ? LastDigit.Seven : LastDigit.One;
[Theory]
[InlineData(GpuKernelType.Pow2Mod, false)]
[InlineData(GpuKernelType.Incremental, false)]
[InlineData(GpuKernelType.Pow2Mod, true)]
[Trait("Category", "Fast")]
public void Scan_handles_various_prime_exponents(GpuKernelType type, bool useGpuOrder)
{
var tester = new MersenneNumberOrderGpuTester(type, useGpuOrder);
if (type == GpuKernelType.Pow2Mod)
{
RunCase(tester, 23UL, 1UL, expectedPrime: false);
RunCase(tester, 29UL, 36UL, expectedPrime: false);
}
RunCase(tester, 89UL, 1_000UL, expectedPrime: true);
RunCase(tester, 127UL, 1_000UL, expectedPrime: true);
}
[Fact]
[Trait("Category", "Fast")]
public void Scan_order_gpu_handles_inaccurate_small_cycle_entries()
{
const ulong exponent = 23UL;
const ulong divisor = 47UL; // 47 | M_23
string tempPath = Path.GetTempFileName();
try
{
using (var writer = new BinaryWriter(File.Open(tempPath, FileMode.Create, FileAccess.Write, FileShare.Read)))
{
writer.Write(divisor);
writer.Write((ulong)uint.MaxValue);
}
var cycles = MersenneDivisorCyclesGpu.Shared;
var tableField = typeof(MersenneDivisorCyclesGpu).GetField("_table", BindingFlags.NonPublic | BindingFlags.Instance)!;
var smallCyclesField = typeof(MersenneDivisorCyclesGpu).GetField("_smallCycles", BindingFlags.NonPublic | BindingFlags.Instance)!;
var originalTable = ((List<(ulong Divisor, ulong Cycle)>)tableField.GetValue(cycles)!).Select(x => x).ToList();
var originalSmall = (ulong[]?)smallCyclesField.GetValue(cycles);
ulong[]? backupSmall = originalSmall is null ? null : (ulong[])originalSmall.Clone();
cycles.LoadFrom(tempPath);
try
{
var tester = new MersenneNumberOrderGpuTester(GpuKernelType.Pow2Mod, useGpuOrder: false);
bool isPrime = true;
tester.Scan(
exponent,
(UInt128)exponent << 1,
GetLastDigit(exponent),
(UInt128)10UL,
ref isPrime);
isPrime.Should().BeFalse();
}
finally
{
tableField.SetValue(cycles, originalTable);
smallCyclesField.SetValue(cycles, backupSmall);
}
}
finally
{
File.Delete(tempPath);
}
}
private static void RunCase(MersenneNumberOrderGpuTester tester, ulong exponent, ulong maxK, bool expectedPrime)
{
bool isPrime = true;
tester.Scan(exponent, (UInt128)exponent << 1, GetLastDigit(exponent), (UInt128)maxK, ref isPrime);
isPrime.Should().Be(expectedPrime);
}
}