Tiny cleanup
This commit is contained in:
1 parent
2d024cc708
commit
9a7382fd80
3 files changed
+187
-187
No files matched your search
@@ -26,20 +26,20 @@ internal static class Program
|
|||||||
private static int _primeCount;
|
private static int _primeCount;
|
||||||
private static bool _primeFoundAfterInit;
|
private static bool _primeFoundAfterInit;
|
||||||
private static bool _useGcdFilter;
|
private static bool _useGcdFilter;
|
||||||
private static bool _useDivisor;
|
private static bool _useDivisor;
|
||||||
private static bool _useResidueMode;
|
private static bool _useResidueMode;
|
||||||
private static UInt128 _divisor;
|
private static UInt128 _divisor;
|
||||||
private static MersenneNumberDivisorGpuTester? _divisorTester;
|
private static MersenneNumberDivisorGpuTester? _divisorTester;
|
||||||
private static ulong? _orderWarmupLimitOverride;
|
private static ulong? _orderWarmupLimitOverride;
|
||||||
private static unsafe delegate*<ulong, ref ulong, ulong> _transformP;
|
private static unsafe delegate*<ulong, ref ulong, ulong> _transformP;
|
||||||
private static long _state;
|
private static long _state;
|
||||||
private static bool _limitReached;
|
private static bool _limitReached;
|
||||||
private static string? _resultsDir;
|
private static string? _resultsDir;
|
||||||
private static string? _resultsPrefix;
|
private static string? _resultsPrefix;
|
||||||
private static readonly Optimized PrimeIterator = new();
|
private static readonly Optimized PrimeIterator = new();
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static bool _lastCompositeP;
|
private static bool _lastCompositeP;
|
||||||
|
|
||||||
// RLE/bit-pattern filtering options
|
// RLE/bit-pattern filtering options
|
||||||
private static string? _rleBlacklistPath;
|
private static string? _rleBlacklistPath;
|
||||||
@@ -414,20 +414,20 @@ internal static class Program
|
|||||||
|
|
||||||
Console.WriteLine("Divisor cycles are ready");
|
Console.WriteLine("Divisor cycles are ready");
|
||||||
|
|
||||||
_useDivisor = useDivisor;
|
_useDivisor = useDivisor;
|
||||||
_useResidueMode = useResidue;
|
_useResidueMode = useResidue;
|
||||||
_divisor = divisor;
|
_divisor = divisor;
|
||||||
if (useBitTransform)
|
if (useBitTransform)
|
||||||
{
|
{
|
||||||
_transformP = &TransformPBit;
|
_transformP = &TransformPBit;
|
||||||
}
|
}
|
||||||
else if (useResidue)
|
else if (useResidue)
|
||||||
{
|
{
|
||||||
_transformP = &TransformPAdd;
|
_transformP = &TransformPAdd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_transformP = &TransformPAddPrimes;
|
_transformP = &TransformPAddPrimes;
|
||||||
}
|
}
|
||||||
PResidue = new ThreadLocal<ModResidueTracker>(() => new ModResidueTracker(ResidueModel.Identity, initialNumber: currentP, initialized: true), trackAllValues: true);
|
PResidue = new ThreadLocal<ModResidueTracker>(() => new ModResidueTracker(ResidueModel.Identity, initialNumber: currentP, initialized: true), trackAllValues: true);
|
||||||
PrimeTesters = new ThreadLocal<PrimeTester>(() => new PrimeTester(), trackAllValues: true);
|
PrimeTesters = new ThreadLocal<PrimeTester>(() => new PrimeTester(), trackAllValues: true);
|
||||||
@@ -435,20 +435,20 @@ internal static class Program
|
|||||||
// Initialize per-thread p residue tracker (Identity model) at currentP
|
// Initialize per-thread p residue tracker (Identity model) at currentP
|
||||||
if (!useDivisor)
|
if (!useDivisor)
|
||||||
{
|
{
|
||||||
MersenneTesters = new ThreadLocal<MersenneNumberTester>(() =>
|
MersenneTesters = new ThreadLocal<MersenneNumberTester>(() =>
|
||||||
{
|
{
|
||||||
var tester = new MersenneNumberTester(
|
var tester = new MersenneNumberTester(
|
||||||
useIncremental: !useLucas,
|
useIncremental: !useLucas,
|
||||||
useOrderCache: false,
|
useOrderCache: false,
|
||||||
kernelType: kernelType,
|
kernelType: kernelType,
|
||||||
useModuloWorkaround: useModuloWorkaround,
|
useModuloWorkaround: useModuloWorkaround,
|
||||||
useOrder: useOrder,
|
useOrder: useOrder,
|
||||||
useGpuLucas: mersenneOnGpu,
|
useGpuLucas: mersenneOnGpu,
|
||||||
useGpuScan: mersenneOnGpu,
|
useGpuScan: mersenneOnGpu,
|
||||||
useGpuOrder: orderOnGpu,
|
useGpuOrder: orderOnGpu,
|
||||||
useResidue: useResidue,
|
useResidue: useResidue,
|
||||||
maxK: residueKMax,
|
maxK: residueKMax,
|
||||||
residueDivisorSets: divisorCyclesSearchLimit);
|
residueDivisorSets: divisorCyclesSearchLimit);
|
||||||
if (!useLucas)
|
if (!useLucas)
|
||||||
{
|
{
|
||||||
tester.WarmUpOrders(currentP, _orderWarmupLimitOverride ?? 5_000_000UL);
|
tester.WarmUpOrders(currentP, _orderWarmupLimitOverride ?? 5_000_000UL);
|
||||||
@@ -732,7 +732,7 @@ internal static class Program
|
|||||||
Console.WriteLine(" --divisor-cycles-device=cpu|gpu device for cycles generation (default gpu)");
|
Console.WriteLine(" --divisor-cycles-device=cpu|gpu device for cycles generation (default gpu)");
|
||||||
Console.WriteLine(" --divisor-cycles-batch-size=<value> batch size for cycles generation (default 512)");
|
Console.WriteLine(" --divisor-cycles-batch-size=<value> batch size for cycles generation (default 512)");
|
||||||
Console.WriteLine(" --divisor-cycles-continue continue divisor cycles generation");
|
Console.WriteLine(" --divisor-cycles-continue continue divisor cycles generation");
|
||||||
Console.WriteLine(" --divisor-cycles-limit=<value> cycle search iterations when --mersenne=divisor or residue");
|
Console.WriteLine(" --divisor-cycles-limit=<value> cycle search iterations when --mersenne=divisor or residue");
|
||||||
|
|
||||||
Console.WriteLine(" --use-order test primality via q order");
|
Console.WriteLine(" --use-order test primality via q order");
|
||||||
Console.WriteLine(" --workaround-mod avoid '%' operator on the GPU");
|
Console.WriteLine(" --workaround-mod avoid '%' operator on the GPU");
|
||||||
@@ -790,30 +790,30 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect)
|
private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect)
|
||||||
{
|
{
|
||||||
if (isPerfect)
|
if (isPerfect)
|
||||||
{
|
{
|
||||||
int newCount = Interlocked.Increment(ref _primeCount);
|
int newCount = Interlocked.Increment(ref _primeCount);
|
||||||
if (newCount >= 2)
|
if (newCount >= 2)
|
||||||
{
|
{
|
||||||
Volatile.Write(ref _primeFoundAfterInit, true);
|
Volatile.Write(ref _primeFoundAfterInit, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_useResidueMode && _lastCompositeP)
|
if (_useResidueMode && _lastCompositeP)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool primeFlag = false, printToConsole = false;
|
bool primeFlag = false, printToConsole = false;
|
||||||
|
|
||||||
StringBuilder localBuilder = StringBuilderPool.Rent();
|
StringBuilder localBuilder = StringBuilderPool.Rent();
|
||||||
_ = localBuilder
|
_ = localBuilder
|
||||||
.Append(currentP).Append(',')
|
.Append(currentP).Append(',')
|
||||||
.Append(searchedMersenne).Append(',')
|
.Append(searchedMersenne).Append(',')
|
||||||
.Append(detailedCheck).Append(',')
|
.Append(detailedCheck).Append(',')
|
||||||
.Append(isPerfect).Append('\n');
|
.Append(isPerfect).Append('\n');
|
||||||
|
|
||||||
lock (Sync)
|
lock (Sync)
|
||||||
{
|
{
|
||||||
@@ -1011,20 +1011,20 @@ internal static class Program
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static bool IsEvenPerfectCandidate(ulong p, ulong divisorCyclesSearchLimit) => IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out _, out _);
|
internal static bool IsEvenPerfectCandidate(ulong p, ulong divisorCyclesSearchLimit) => IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out _, out _);
|
||||||
|
|
||||||
internal static bool IsEvenPerfectCandidate(ulong p, ulong divisorCyclesSearchLimit, out bool searchedMersenne, out bool detailedCheck)
|
internal static bool IsEvenPerfectCandidate(ulong p, ulong divisorCyclesSearchLimit, out bool searchedMersenne, out bool detailedCheck)
|
||||||
{
|
{
|
||||||
searchedMersenne = false;
|
searchedMersenne = false;
|
||||||
detailedCheck = false;
|
detailedCheck = false;
|
||||||
_lastCompositeP = false;
|
_lastCompositeP = false;
|
||||||
|
|
||||||
if (_useGcdFilter && IsCompositeByGcd(p))
|
if (_useGcdFilter && IsCompositeByGcd(p))
|
||||||
{
|
{
|
||||||
_lastCompositeP = true;
|
_lastCompositeP = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: RLE blacklist and binary-threshold filters on p (safe only when configured)
|
// Optional: RLE blacklist and binary-threshold filters on p (safe only when configured)
|
||||||
if (p <= _rleHardMaxP)
|
if (p <= _rleHardMaxP)
|
||||||
{
|
{
|
||||||
if (!_rleOnlyLast7 || (p % 10UL) == 7UL)
|
if (!_rleOnlyLast7 || (p % 10UL) == 7UL)
|
||||||
{
|
{
|
||||||
@@ -1058,36 +1058,36 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast residue-based composite check for p using small primes
|
// Fast residue-based composite check for p using small primes
|
||||||
if (!_useDivisor && IsCompositeByResidues(p))
|
if (!_useDivisor && IsCompositeByResidues(p))
|
||||||
{
|
{
|
||||||
searchedMersenne = false;
|
searchedMersenne = false;
|
||||||
detailedCheck = false;
|
detailedCheck = false;
|
||||||
_lastCompositeP = true;
|
_lastCompositeP = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If primes-device=gpu, route p primality through GPU-assisted sieve (optional MR later)
|
// If primes-device=gpu, route p primality through GPU-assisted sieve (optional MR later)
|
||||||
// TODO: Add deterministic Miller–Rabin rounds in GPU path for 64-bit range.
|
// TODO: Add deterministic Miller–Rabin rounds in GPU path for 64-bit range.
|
||||||
bool isPrimeP = GpuContextPool.ForceCpu
|
bool isPrimeP = GpuContextPool.ForceCpu
|
||||||
? PrimeTesters.Value!.IsPrime(p, CancellationToken.None)
|
? PrimeTesters.Value!.IsPrime(p, CancellationToken.None)
|
||||||
: PrimeTesters.Value!.IsPrimeGpu(p, CancellationToken.None);
|
: PrimeTesters.Value!.IsPrimeGpu(p, CancellationToken.None);
|
||||||
if (!isPrimeP)
|
if (!isPrimeP)
|
||||||
{
|
{
|
||||||
_lastCompositeP = true;
|
_lastCompositeP = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchedMersenne = true;
|
searchedMersenne = true;
|
||||||
if (_useDivisor)
|
if (_useDivisor)
|
||||||
{
|
{
|
||||||
return _divisorTester!.IsPrime(p, _divisor, divisorCyclesSearchLimit, out detailedCheck);
|
return _divisorTester!.IsPrime(p, _divisor, divisorCyclesSearchLimit, out detailedCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mersennePrime = MersenneTesters.Value!.IsMersennePrime(p, out bool residueExhausted);
|
bool mersennePrime = MersenneTesters.Value!.IsMersennePrime(p, out bool residueExhausted);
|
||||||
detailedCheck = residueExhausted;
|
detailedCheck = residueExhausted;
|
||||||
return mersennePrime;
|
return mersennePrime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use ModResidueTracker with a small set of primes to pre-filter composite p.
|
// Use ModResidueTracker with a small set of primes to pre-filter composite p.
|
||||||
private static bool IsCompositeByResidues(ulong p)
|
private static bool IsCompositeByResidues(ulong p)
|
||||||
|
|||||||
@@ -11,103 +11,103 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
// candidates without launching heavy kernels. Consider a device-visible constant buffer per-accelerator
|
// candidates without launching heavy kernels. Consider a device-visible constant buffer per-accelerator
|
||||||
// via GpuKernelPool to avoid host round-trips.
|
// via GpuKernelPool to avoid host round-trips.
|
||||||
|
|
||||||
// GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1.
|
// GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1.
|
||||||
public void Scan(
|
public void Scan(
|
||||||
ulong exponent,
|
ulong exponent,
|
||||||
UInt128 twoP,
|
UInt128 twoP,
|
||||||
bool lastIsSeven,
|
bool lastIsSeven,
|
||||||
UInt128 perSetLimit,
|
UInt128 perSetLimit,
|
||||||
ulong setCount,
|
ulong setCount,
|
||||||
UInt128 overallLimit,
|
UInt128 overallLimit,
|
||||||
ref bool isPrime,
|
ref bool isPrime,
|
||||||
ref bool divisorsExhausted)
|
ref bool divisorsExhausted)
|
||||||
{
|
{
|
||||||
if (setCount == 0UL || perSetLimit == UInt128.Zero || overallLimit == UInt128.Zero)
|
if (setCount == 0UL || perSetLimit == UInt128.Zero || overallLimit == UInt128.Zero)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = gpuLease.Accelerator;
|
||||||
// Ensure device has small cycles and primes tables for in-kernel lookup
|
// Ensure device has small cycles and primes tables for in-kernel lookup
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
ResiduePrimeViews primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(accelerator);
|
ResiduePrimeViews primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(accelerator);
|
||||||
int batchSize = GpuConstants.ScanBatchSize;
|
int batchSize = GpuConstants.ScanBatchSize;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||||
var kernel = gpuLease.Pow2ModKernel;
|
var kernel = gpuLease.Pow2ModKernel;
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||||
|
|
||||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||||
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
||||||
UInt128 batchSize128 = (UInt128)batchSize;
|
UInt128 batchSize128 = (UInt128)batchSize;
|
||||||
UInt128 limitInclusive = overallLimit + UInt128.One;
|
UInt128 limitInclusive = overallLimit + UInt128.One;
|
||||||
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 (ulong setIndex = 0; setIndex < setCount && Volatile.Read(ref isPrime); setIndex++)
|
||||||
{
|
{
|
||||||
UInt128 setOffset = perSetLimit * (UInt128)setIndex;
|
UInt128 setOffset = perSetLimit * (UInt128)setIndex;
|
||||||
UInt128 setStart = setOffset + UInt128.One;
|
UInt128 setStart = setOffset + UInt128.One;
|
||||||
if (setStart >= limitInclusive)
|
if (setStart >= limitInclusive)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 setLimitExclusive = setOffset + perSetLimit + UInt128.One;
|
UInt128 setLimitExclusive = setOffset + perSetLimit + UInt128.One;
|
||||||
if (setLimitExclusive > limitInclusive)
|
if (setLimitExclusive > limitInclusive)
|
||||||
{
|
{
|
||||||
setLimitExclusive = limitInclusive;
|
setLimitExclusive = limitInclusive;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 kStart = setStart;
|
UInt128 kStart = setStart;
|
||||||
while (kStart < setLimitExclusive && Volatile.Read(ref isPrime))
|
while (kStart < setLimitExclusive && Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
UInt128 remaining = setLimitExclusive - kStart;
|
UInt128 remaining = setLimitExclusive - kStart;
|
||||||
int currentSize = remaining > batchSize128 ? batchSize : (int)remaining;
|
int currentSize = remaining > batchSize128 ? batchSize : (int)remaining;
|
||||||
if (currentSize <= 0)
|
if (currentSize <= 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
orders = orderArray.AsSpan(0, currentSize);
|
orders = orderArray.AsSpan(0, currentSize);
|
||||||
|
|
||||||
UInt128 q = twoP * kStart + UInt128.One;
|
UInt128 q = twoP * kStart + UInt128.One;
|
||||||
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
||||||
var ra = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
var ra = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
||||||
|
|
||||||
kernel(currentSize, exponent, twoPGpu, (GpuUInt128)kStart, last, 0UL,
|
kernel(currentSize, exponent, twoPGpu, (GpuUInt128)kStart, last, 0UL,
|
||||||
ra, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven, primeViews.LastOnePow2, primeViews.LastSevenPow2);
|
ra, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven, primeViews.LastOnePow2, primeViews.LastSevenPow2);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
||||||
if (!Volatile.Read(ref isPrime))
|
if (!Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < currentSize; i++)
|
for (int i = 0; i < currentSize; i++)
|
||||||
{
|
{
|
||||||
if (orders[i] != 0UL)
|
if (orders[i] != 0UL)
|
||||||
{
|
{
|
||||||
Volatile.Write(ref isPrime, false);
|
Volatile.Write(ref isPrime, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kStart += batchSize128;
|
kStart += batchSize128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ArrayPool<ulong>.Shared.Return(orderArray);
|
ArrayPool<ulong>.Shared.Return(orderArray);
|
||||||
orderBuffer.Dispose();
|
orderBuffer.Dispose();
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
divisorsExhausted = true;
|
divisorsExhausted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,6 @@ public static class PerfectNumberConstants
|
|||||||
public const ulong BiggestKnownEvenPerfectP = 136279841UL;
|
public const ulong BiggestKnownEvenPerfectP = 136279841UL;
|
||||||
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
|
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 ulong ExtraDivisorCycleSearchLimit = 64UL;
|
public const ulong ExtraDivisorCycleSearchLimit = 64UL;
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user