No. of divisor cycle iterations made configurable

This commit is contained in:
Marek Lemańczyk committed 2025-09-11 01:20:15 +02:00
1 parent c8c80f2f91
commit f17f83e326
3 files changed
+299 -291

No files matched your search

@@ -7,51 +7,51 @@ namespace PerfectNumbers.Core.Gpu;
public sealed class MersenneNumberDivisorGpuTester
{
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ulong, ulong, ArrayView<byte>>> _kernelCache = new();
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ulong, ulong, ArrayView<byte>>> _kernelCache = new();
private Action<Index1D, ulong, ulong, ArrayView<byte>> GetKernel(Accelerator accelerator) =>
_kernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, ulong, ulong, ArrayView<byte>>(Kernel));
private Action<Index1D, ulong, ulong, ArrayView<byte>> GetKernel(Accelerator accelerator) =>
_kernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, ulong, ulong, ArrayView<byte>>(Kernel));
public bool IsDivisible(ulong exponent, ulong divisor)
{
var gpu = GpuContextPool.RentPreferred(preferCpu: false);
var accelerator = gpu.Accelerator;
var kernel = GetKernel(accelerator);
using var resultBuffer = accelerator.Allocate1D<byte>(1);
kernel(1, exponent, divisor, resultBuffer.View);
accelerator.Synchronize();
bool divisible = resultBuffer.GetAsArray1D()[0] != 0;
gpu.Dispose();
return divisible;
}
public bool IsDivisible(ulong exponent, ulong divisor)
{
var gpu = GpuContextPool.RentPreferred(preferCpu: false);
var accelerator = gpu.Accelerator;
var kernel = GetKernel(accelerator);
using var resultBuffer = accelerator.Allocate1D<byte>(1);
kernel(1, exponent, divisor, resultBuffer.View);
accelerator.Synchronize();
bool divisible = resultBuffer.GetAsArray1D()[0] != 0;
gpu.Dispose();
return divisible;
}
private static void Kernel(Index1D _, ulong exponent, ulong divisor, ArrayView<byte> result)
{
if (divisor <= 1UL)
{
result[0] = 0;
return;
}
private static void Kernel(Index1D _, ulong exponent, ulong divisor, ArrayView<byte> result)
{
if (divisor <= 1UL)
{
result[0] = 0;
return;
}
int x = 63 - XMath.LeadingZeroCount(divisor);
if (x == 0)
{
var mod = new GpuUInt128(0UL, divisor);
var temp = GpuUInt128.Pow2Mod(exponent, mod);
result[0] = temp.High == 0UL && temp.Low == 1UL ? (byte)1 : (byte)0;
return;
}
int x = 63 - XMath.LeadingZeroCount(divisor);
if (x == 0)
{
var mod = new GpuUInt128(0UL, divisor);
var temp = GpuUInt128.Pow2Mod(exponent, mod);
result[0] = temp.High == 0UL && temp.Low == 1UL ? (byte)1 : (byte)0;
return;
}
ulong ux = (ulong)x;
ulong q = exponent / ux;
ulong r = exponent % ux;
ulong pow2x = 1UL << x;
ulong y = divisor - pow2x;
var modVal = new GpuUInt128(0UL, divisor);
var baseVal = new GpuUInt128(0UL, pow2x); // 2^x ≡ -y (mod divisor)
var part1 = baseVal.ModPow(q, modVal);
var part2 = GpuUInt128.Pow2Mod(r, modVal);
var rem = part1.MulMod(part2, modVal);
result[0] = rem.High == 0UL && rem.Low == 1UL ? (byte)1 : (byte)0;
}
ulong ux = (ulong)x;
ulong q = exponent / ux;
ulong r = exponent % ux;
ulong pow2x = 1UL << x;
ulong y = divisor - pow2x;
var modVal = new GpuUInt128(0UL, divisor);
var baseVal = new GpuUInt128(0UL, pow2x); // 2^x ≡ -y (mod divisor)
var part1 = baseVal.ModPow(q, modVal);
var part2 = GpuUInt128.Pow2Mod(r, modVal);
var rem = part1.MulMod(part2, modVal);
result[0] = rem.High == 0UL && rem.Low == 1UL ? (byte)1 : (byte)0;
}
}
@@ -4,5 +4,7 @@ public static class PerfectNumberConstants
{
public const ulong BiggestKnownEvenPerfectP = 136279841UL;
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
public const int MaxQForDivisorCycles = 4_000_000;
public const int MaxQForDivisorCycles = 4_000_000;
public const int ExtraDivisorCycleSearchLimit = 64;
}