Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eae153e4a4 | ||
|
|
574e4b8007 |
No files matched your search
@@ -515,9 +515,7 @@ internal static class Program
|
|||||||
{
|
{
|
||||||
_byDivisorTester = mersenneOnGpu
|
_byDivisorTester = mersenneOnGpu
|
||||||
? new MersenneNumberDivisorByDivisorGpuTester()
|
? new MersenneNumberDivisorByDivisorGpuTester()
|
||||||
: new MersenneNumberDivisorByDivisorCpuTester(
|
: new MersenneNumberDivisorByDivisorCpuTester();
|
||||||
useGpuPow2Mod: !GpuContextPool.ForceCpu,
|
|
||||||
useGpuCycleComputation: orderOnGpu);
|
|
||||||
_byDivisorTester.BatchSize = scanBatchSize;
|
_byDivisorTester.BatchSize = scanBatchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Collections.Concurrent;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using PerfectNumbers.Core;
|
using PerfectNumbers.Core;
|
||||||
using PerfectNumbers.Core.Gpu;
|
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Cpu;
|
namespace PerfectNumbers.Core.Cpu;
|
||||||
|
|
||||||
@@ -11,18 +10,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
{
|
{
|
||||||
private readonly object _sync = new();
|
private readonly object _sync = new();
|
||||||
private readonly ConcurrentBag<DivisorScanSession> _sessionPool = new();
|
private readonly ConcurrentBag<DivisorScanSession> _sessionPool = new();
|
||||||
private readonly bool _useGpuPow2Mod;
|
|
||||||
private readonly bool _useGpuCycleComputation;
|
|
||||||
private ulong _divisorLimit;
|
private ulong _divisorLimit;
|
||||||
private ulong _lastStatusDivisor;
|
private ulong _lastStatusDivisor;
|
||||||
private bool _isConfigured;
|
private bool _isConfigured;
|
||||||
private int _batchSize = 1_024;
|
private int _batchSize = 1_024;
|
||||||
|
|
||||||
public MersenneNumberDivisorByDivisorCpuTester(bool useGpuPow2Mod = false, bool useGpuCycleComputation = false)
|
|
||||||
{
|
|
||||||
_useGpuPow2Mod = useGpuPow2Mod;
|
|
||||||
_useGpuCycleComputation = useGpuCycleComputation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BatchSize
|
public int BatchSize
|
||||||
{
|
{
|
||||||
@@ -88,9 +80,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong processedCount;
|
ulong processedCount = 0UL;
|
||||||
ulong lastProcessed;
|
ulong lastProcessed = 0UL;
|
||||||
bool processedAll;
|
bool processedAll = false;
|
||||||
|
|
||||||
bool composite = CheckDivisors(
|
bool composite = CheckDivisors(
|
||||||
prime,
|
prime,
|
||||||
@@ -198,8 +190,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>? factorCache = null;
|
Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>? factorCache = null;
|
||||||
Dictionary<ulong, ulong>? cycleRemainderCache = null;
|
|
||||||
CycleHint cycleHint = default;
|
|
||||||
DivisorCycleCache cycleCache = DivisorCycleCache.Shared;
|
DivisorCycleCache cycleCache = DivisorCycleCache.Shared;
|
||||||
|
|
||||||
byte step10 = (byte)(step % 10UL);
|
byte step10 = (byte)(step % 10UL);
|
||||||
@@ -233,14 +223,34 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
if (admissible && (remainder8 == 1 || remainder8 == 7) && remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0)
|
if (admissible && (remainder8 == 1 || remainder8 == 7) && remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0)
|
||||||
{
|
{
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataCache.Get(candidate);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorDataCache.Get(candidate);
|
||||||
if (TryResolveDivisorCycle(candidate, prime, divisorData, cycleCache, ref factorCache, ref cycleHint, out ulong divisorCycle) && divisorCycle != 0UL)
|
ulong divisorCycle;
|
||||||
|
|
||||||
|
if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles)
|
||||||
{
|
{
|
||||||
if (CheckDivisor(prime, candidate, divisorCycle, divisorData, ref cycleRemainderCache, ref cycleHint) != 0)
|
divisorCycle = cycleCache.GetCycleLength(candidate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
factorCache ??= new Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>(8);
|
||||||
|
if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponent(candidate, prime, divisorData, factorCache, out divisorCycle) || divisorCycle == 0UL)
|
||||||
{
|
{
|
||||||
processedAll = true;
|
divisorCycle = cycleCache.GetCycleLength(candidate);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (divisorCycle == prime)
|
||||||
|
{
|
||||||
|
// A cycle equal to the tested exponent (which is prime in this path)
|
||||||
|
// guarantees that the candidate divides the corresponding Mersenne
|
||||||
|
// number because the order of 2 modulo the divisor is exactly p.
|
||||||
|
processedAll = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (divisorCycle == 0UL)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Divisor cycle was not calculated for {prime}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
divisor += step;
|
divisor += step;
|
||||||
@@ -256,152 +266,12 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte CheckDivisor(
|
private static byte CheckDivisor(ulong prime, ulong divisorCycle, in MontgomeryDivisorData divisorData)
|
||||||
ulong prime,
|
|
||||||
ulong divisor,
|
|
||||||
ulong divisorCycle,
|
|
||||||
in MontgomeryDivisorData divisorData,
|
|
||||||
ref Dictionary<ulong, ulong>? cycleRemainders,
|
|
||||||
ref CycleHint cycleHint)
|
|
||||||
{
|
{
|
||||||
if (divisorCycle == 0UL)
|
ulong residue = prime.Pow2MontgomeryModWithCycle(divisorCycle, divisorData);
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Cycle length resolution returned zero for divisor {divisor}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<ulong, ulong>? remainderCache = cycleRemainders;
|
|
||||||
if (_useGpuPow2Mod && remainderCache is null)
|
|
||||||
{
|
|
||||||
remainderCache = new Dictionary<ulong, ulong>(8);
|
|
||||||
cycleRemainders = remainderCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong reducedExponent;
|
|
||||||
if (remainderCache is not null && remainderCache.TryGetValue(divisorCycle, out ulong cachedRemainder))
|
|
||||||
{
|
|
||||||
reducedExponent = cachedRemainder;
|
|
||||||
}
|
|
||||||
else if (cycleHint.HasCycle && cycleHint.LastCycleLength == divisorCycle)
|
|
||||||
{
|
|
||||||
reducedExponent = cycleHint.LastReducedExponent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reducedExponent = prime % divisorCycle;
|
|
||||||
if (remainderCache is not null)
|
|
||||||
{
|
|
||||||
remainderCache[divisorCycle] = reducedExponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleHint.LastCycleLength = divisorCycle;
|
|
||||||
cycleHint.LastReducedExponent = reducedExponent;
|
|
||||||
cycleHint.HasCycle = true;
|
|
||||||
|
|
||||||
if (_useGpuPow2Mod && remainderCache is not null)
|
|
||||||
{
|
|
||||||
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(reducedExponent, divisor, out ulong remainder, divisorData);
|
|
||||||
if (status == GpuPow2ModStatus.Success)
|
|
||||||
{
|
|
||||||
return remainder == 1UL ? (byte)1 : (byte)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimeOrderGpuHeuristics.ReportPow2Failure(
|
|
||||||
"by-divisor residue scan",
|
|
||||||
divisor,
|
|
||||||
status);
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong residue = reducedExponent.Pow2MontgomeryModFromCycleRemainder(divisorData);
|
|
||||||
return residue == 1UL ? (byte)1 : (byte)0;
|
return residue == 1UL ? (byte)1 : (byte)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryResolveDivisorCycle(
|
|
||||||
ulong divisor,
|
|
||||||
ulong prime,
|
|
||||||
in MontgomeryDivisorData divisorData,
|
|
||||||
DivisorCycleCache cycleCache,
|
|
||||||
ref Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>? factorCache,
|
|
||||||
ref CycleHint cycleHint,
|
|
||||||
out ulong cycleLength)
|
|
||||||
{
|
|
||||||
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
|
|
||||||
{
|
|
||||||
cycleLength = cycleCache.GetCycleLength(divisor);
|
|
||||||
if (cycleLength == 0UL)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Missing cached cycle length for divisor {divisor}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleHint.LastCycleLength = cycleLength;
|
|
||||||
cycleHint.HasCycle = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_useGpuCycleComputation && TryCalculateCycleLengthGpu(divisor, prime, divisorData, ref cycleHint, out cycleLength))
|
|
||||||
{
|
|
||||||
return cycleLength != 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
factorCache ??= new Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>(8);
|
|
||||||
if (MersenneDivisorCycles.TryCalculateCycleLengthForExponent(
|
|
||||||
divisor,
|
|
||||||
prime,
|
|
||||||
divisorData,
|
|
||||||
factorCache,
|
|
||||||
out cycleLength,
|
|
||||||
allowGpuPow2: _useGpuPow2Mod) && cycleLength != 0UL)
|
|
||||||
{
|
|
||||||
cycleHint.LastCycleLength = cycleLength;
|
|
||||||
cycleHint.HasCycle = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleLength = cycleCache.GetCycleLength(divisor);
|
|
||||||
if (cycleLength == 0UL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleHint.LastCycleLength = cycleLength;
|
|
||||||
cycleHint.HasCycle = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryCalculateCycleLengthGpu(
|
|
||||||
ulong divisor,
|
|
||||||
ulong prime,
|
|
||||||
in MontgomeryDivisorData divisorData,
|
|
||||||
ref CycleHint cycleHint,
|
|
||||||
out ulong cycleLength)
|
|
||||||
{
|
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig config = PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault;
|
|
||||||
ulong? previousOrder = cycleHint.HasCycle ? cycleHint.LastCycleLength : null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!PrimeOrderGpuHeuristics.TryCalculateOrder(divisor, previousOrder, config, divisorData, out PrimeOrderCalculator.PrimeOrderResult result))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("GPU requested fallback.");
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleLength = result.Order;
|
|
||||||
if (cycleLength == 0UL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleHint.LastCycleLength = cycleLength;
|
|
||||||
cycleHint.HasCycle = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException ex)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine($"GPU cycle length computation failed for divisor {divisor}: {ex.Message}");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte AddMod(byte value, byte delta, byte modulus)
|
private static byte AddMod(byte value, byte delta, byte modulus)
|
||||||
{
|
{
|
||||||
int sum = value + delta;
|
int sum = value + delta;
|
||||||
@@ -428,9 +298,16 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
ulong total = _lastStatusDivisor + processedCount;
|
ulong total = _lastStatusDivisor + processedCount;
|
||||||
// TODO: Replace this modulo with the ring-buffer style counter (subtract loop) used in the fast CLI
|
if (total >= interval)
|
||||||
// status benchmarks so we avoid `%` in this hot loop while still wrapping progress correctly.
|
{
|
||||||
_lastStatusDivisor = total % interval;
|
do
|
||||||
|
{
|
||||||
|
total -= interval;
|
||||||
|
}
|
||||||
|
while (total >= interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastStatusDivisor = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong ComputeDivisorLimitFromMaxPrime(ulong maxPrime)
|
private static ulong ComputeDivisorLimitFromMaxPrime(ulong maxPrime)
|
||||||
@@ -448,13 +325,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
return (1UL << (int)(maxPrime - 1UL)) - 1UL;
|
return (1UL << (int)(maxPrime - 1UL)) - 1UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct CycleHint
|
|
||||||
{
|
|
||||||
public ulong LastCycleLength;
|
|
||||||
public ulong LastReducedExponent;
|
|
||||||
public bool HasCycle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong ComputeAllowedMaxDivisor(ulong prime, ulong divisorLimit)
|
private static ulong ComputeAllowedMaxDivisor(ulong prime, ulong divisorLimit)
|
||||||
{
|
{
|
||||||
if (prime <= 1UL)
|
if (prime <= 1UL)
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ using System.Collections.Concurrent;
|
|||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Globalization;
|
|
||||||
using PerfectNumbers.Core;
|
using PerfectNumbers.Core;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using ILGPU.Runtime.OpenCL;
|
using ILGPU.Runtime.OpenCL;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
internal enum GpuPow2ModStatus
|
internal enum GpuPow2ModStatus
|
||||||
@@ -29,25 +27,6 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
private static readonly ConcurrentDictionary<Accelerator, OrderKernelLauncher> OrderKernelCache = new();
|
private static readonly ConcurrentDictionary<Accelerator, OrderKernelLauncher> OrderKernelCache = new();
|
||||||
private static readonly ConcurrentDictionary<Accelerator, SmallPrimeDeviceCache> SmallPrimeDeviceCaches = new();
|
private static readonly ConcurrentDictionary<Accelerator, SmallPrimeDeviceCache> SmallPrimeDeviceCaches = new();
|
||||||
|
|
||||||
private static void ReportPow2FailureCore(string context, string modulusDescription, GpuPow2ModStatus status)
|
|
||||||
{
|
|
||||||
string message = $"GPU pow2mod failed with status {status} for divisor {modulusDescription} during {context}.";
|
|
||||||
Console.Error.WriteLine(message);
|
|
||||||
throw new InvalidOperationException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ReportPow2Failure(string context, ulong modulus, GpuPow2ModStatus status)
|
|
||||||
{
|
|
||||||
string modulusDescription = modulus.ToString(CultureInfo.InvariantCulture);
|
|
||||||
ReportPow2FailureCore(context, modulusDescription, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ReportPow2Failure(string context, UInt128 modulus, GpuPow2ModStatus status)
|
|
||||||
{
|
|
||||||
string modulusDescription = modulus.ToString(CultureInfo.InvariantCulture);
|
|
||||||
ReportPow2FailureCore(context, modulusDescription, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct OrderKernelConfig(ulong previousOrder, byte hasPreviousOrder, uint smallFactorLimit, int maxPowChecks, int mode)
|
public readonly struct OrderKernelConfig(ulong previousOrder, byte hasPreviousOrder, uint smallFactorLimit, int maxPowChecks, int mode)
|
||||||
{
|
{
|
||||||
public readonly ulong PreviousOrder = previousOrder;
|
public readonly ulong PreviousOrder = previousOrder;
|
||||||
|
|||||||
@@ -269,8 +269,7 @@ public class MersenneDivisorCycles
|
|||||||
ulong exponent,
|
ulong exponent,
|
||||||
in MontgomeryDivisorData divisorData,
|
in MontgomeryDivisorData divisorData,
|
||||||
Dictionary<ulong, FactorCacheEntry>? factorCache,
|
Dictionary<ulong, FactorCacheEntry>? factorCache,
|
||||||
out ulong cycleLength,
|
out ulong cycleLength)
|
||||||
bool allowGpuPow2 = false)
|
|
||||||
{
|
{
|
||||||
cycleLength = 0UL;
|
cycleLength = 0UL;
|
||||||
|
|
||||||
@@ -291,8 +290,7 @@ public class MersenneDivisorCycles
|
|||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
divisorData,
|
divisorData,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu,
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||||
allowGpuPow2);
|
|
||||||
if (orderResult.Order != 0UL)
|
if (orderResult.Order != 0UL)
|
||||||
{
|
{
|
||||||
cycleLength = orderResult.Order;
|
cycleLength = orderResult.Order;
|
||||||
@@ -329,7 +327,7 @@ public class MersenneDivisorCycles
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cycleLength = ReduceOrder(divisorData, phi, factorCounts, allowGpuPow2);
|
cycleLength = ReduceOrder(divisorData, phi, factorCounts);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +471,7 @@ public class MersenneDivisorCycles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong ReduceOrder(in MontgomeryDivisorData divisorData, ulong initialOrder, Dictionary<ulong, int> factorCounts, bool allowGpuPow2)
|
private static ulong ReduceOrder(in MontgomeryDivisorData divisorData, ulong initialOrder, Dictionary<ulong, int> factorCounts)
|
||||||
{
|
{
|
||||||
if (factorCounts.Count == 0)
|
if (factorCounts.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -507,7 +505,7 @@ public class MersenneDivisorCycles
|
|||||||
}
|
}
|
||||||
|
|
||||||
ulong candidate = order / prime;
|
ulong candidate = order / prime;
|
||||||
if (Pow2EqualsOne(candidate, divisorData, allowGpuPow2))
|
if (candidate.Pow2MontgomeryModWindowed(divisorData, keepMontgomery: false) == 1UL)
|
||||||
{
|
{
|
||||||
order = candidate;
|
order = candidate;
|
||||||
continue;
|
continue;
|
||||||
@@ -525,26 +523,6 @@ public class MersenneDivisorCycles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static bool Pow2EqualsOne(ulong exponent, in MontgomeryDivisorData divisorData, bool allowGpuPow2)
|
|
||||||
{
|
|
||||||
if (allowGpuPow2)
|
|
||||||
{
|
|
||||||
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, divisorData.Modulus, out ulong remainder, divisorData);
|
|
||||||
if (status == GpuPow2ModStatus.Success)
|
|
||||||
{
|
|
||||||
return remainder == 1UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimeOrderGpuHeuristics.ReportPow2Failure(
|
|
||||||
"divisor cycle reduction",
|
|
||||||
divisorData.Modulus,
|
|
||||||
status);
|
|
||||||
}
|
|
||||||
|
|
||||||
return exponent.Pow2MontgomeryModWindowed(divisorData, keepMontgomery: false) == 1UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong PollardRho64(ulong n)
|
private static ulong PollardRho64(ulong n)
|
||||||
{
|
{
|
||||||
if ((n & 1UL) == 0UL)
|
if ((n & 1UL) == 0UL)
|
||||||
@@ -946,7 +924,7 @@ public class MersenneDivisorCycles
|
|||||||
return CalculateCycleLengthFallback(divisor);
|
return CalculateCycleLengthFallback(divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool TryCalculateCycleLengthHeuristic(ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength, bool allowGpuPow2 = false)
|
internal static bool TryCalculateCycleLengthHeuristic(ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength)
|
||||||
{
|
{
|
||||||
if ((divisor & (divisor - 1UL)) == 0UL)
|
if ((divisor & (divisor - 1UL)) == 0UL)
|
||||||
{
|
{
|
||||||
@@ -967,8 +945,7 @@ public class MersenneDivisorCycles
|
|||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
divisorData,
|
divisorData,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu,
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||||
allowGpuPow2);
|
|
||||||
if (orderResult.Order != 0UL)
|
if (orderResult.Order != 0UL)
|
||||||
{
|
{
|
||||||
cycleLength = orderResult.Order;
|
cycleLength = orderResult.Order;
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
PrimeOrderSearchConfig config,
|
PrimeOrderSearchConfig config,
|
||||||
PrimeOrderHeuristicDevice device)
|
PrimeOrderHeuristicDevice device)
|
||||||
{
|
{
|
||||||
bool enableGpuPow2 = device == PrimeOrderHeuristicDevice.Gpu;
|
using var scope = UsePow2Mode(device);
|
||||||
using var scope = UsePow2Mode(device, enableGpuPow2);
|
|
||||||
MontgomeryDivisorData divisorData;
|
MontgomeryDivisorData divisorData;
|
||||||
if (prime <= ulong.MaxValue)
|
if (prime <= ulong.MaxValue)
|
||||||
{
|
{
|
||||||
@@ -52,7 +51,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
ulong prime64 = (ulong)prime;
|
ulong prime64 = (ulong)prime;
|
||||||
divisorData = MontgomeryDivisorData.FromModulus(prime64);
|
divisorData = MontgomeryDivisorData.FromModulus(prime64);
|
||||||
PrimeOrderResult result = Calculate(prime64, previous, divisorData, config, device, enableGpuPow2);
|
PrimeOrderResult result = Calculate(prime64, previous, divisorData, config, device);
|
||||||
return new PrimeOrderResultWide(result.Status, result.Order);
|
return new PrimeOrderResultWide(result.Status, result.Order);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1031,11 +1030,6 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
return wideRemainder;
|
return wideRemainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimeOrderGpuHeuristics.ReportPow2Failure(
|
|
||||||
"wide prime order pow2 check",
|
|
||||||
modulus,
|
|
||||||
wideStatus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return exponent.Pow2MontgomeryModWindowed(modulus);
|
return exponent.Pow2MontgomeryModWindowed(modulus);
|
||||||
|
|||||||
@@ -90,13 +90,13 @@ internal static partial class PrimeOrderCalculator
|
|||||||
private readonly bool _previousAllow;
|
private readonly bool _previousAllow;
|
||||||
private readonly PrimeOrderHeuristicDevice _previousDevice;
|
private readonly PrimeOrderHeuristicDevice _previousDevice;
|
||||||
|
|
||||||
public Pow2ModeScope(PrimeOrderHeuristicDevice device, bool allowGpuPow2)
|
public Pow2ModeScope(PrimeOrderHeuristicDevice device)
|
||||||
{
|
{
|
||||||
_previousInitialized = s_pow2ModeInitialized;
|
_previousInitialized = s_pow2ModeInitialized;
|
||||||
_previousAllow = s_allowGpuPow2;
|
_previousAllow = s_allowGpuPow2;
|
||||||
_previousDevice = s_deviceMode;
|
_previousDevice = s_deviceMode;
|
||||||
s_pow2ModeInitialized = true;
|
s_pow2ModeInitialized = true;
|
||||||
s_allowGpuPow2 = allowGpuPow2;
|
s_allowGpuPow2 = device == PrimeOrderHeuristicDevice.Gpu;
|
||||||
s_deviceMode = device;
|
s_deviceMode = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Pow2ModeScope UsePow2Mode(PrimeOrderHeuristicDevice device, bool allowGpuPow2) => new(device, allowGpuPow2);
|
private static Pow2ModeScope UsePow2Mode(PrimeOrderHeuristicDevice device) => new(device);
|
||||||
|
|
||||||
private static DebugLoggingScope UseDebugLogging(bool enabled) => new(enabled);
|
private static DebugLoggingScope UseDebugLogging(bool enabled) => new(enabled);
|
||||||
|
|
||||||
@@ -154,11 +154,9 @@ internal static partial class PrimeOrderCalculator
|
|||||||
ulong? previousOrder,
|
ulong? previousOrder,
|
||||||
in MontgomeryDivisorData divisorData,
|
in MontgomeryDivisorData divisorData,
|
||||||
PrimeOrderSearchConfig config,
|
PrimeOrderSearchConfig config,
|
||||||
PrimeOrderHeuristicDevice device,
|
PrimeOrderHeuristicDevice device)
|
||||||
bool allowGpuPow2 = false)
|
|
||||||
{
|
{
|
||||||
bool enableGpuPow2 = allowGpuPow2 || device == PrimeOrderHeuristicDevice.Gpu;
|
using var scope = UsePow2Mode(device);
|
||||||
using var scope = UsePow2Mode(device, enableGpuPow2);
|
|
||||||
return CalculateInternal(prime, previousOrder, divisorData, config);
|
return CalculateInternal(prime, previousOrder, divisorData, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,6 +443,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
int powBudget = config.MaxPowChecks <= 0 ? candidates.Count : config.MaxPowChecks;
|
int powBudget = config.MaxPowChecks <= 0 ? candidates.Count : config.MaxPowChecks;
|
||||||
int powUsed = 0;
|
int powUsed = 0;
|
||||||
int candidateCount = candidates.Count;
|
int candidateCount = candidates.Count;
|
||||||
|
bool allowGpuBatch = true;
|
||||||
Span<ulong> candidateSpan = CollectionsMarshal.AsSpan(candidates);
|
Span<ulong> candidateSpan = CollectionsMarshal.AsSpan(candidates);
|
||||||
|
|
||||||
DebugLog(() => $"Checking candidates ({candidateCount} candidates, {powBudget} pow budget)");
|
DebugLog(() => $"Checking candidates ({candidateCount} candidates, {powBudget} pow budget)");
|
||||||
@@ -468,11 +467,9 @@ internal static partial class PrimeOrderCalculator
|
|||||||
bool gpuSuccess = false;
|
bool gpuSuccess = false;
|
||||||
bool gpuStackRemainders = false;
|
bool gpuStackRemainders = false;
|
||||||
GpuPow2ModStatus status = GpuPow2ModStatus.Unavailable;
|
GpuPow2ModStatus status = GpuPow2ModStatus.Unavailable;
|
||||||
bool attemptedGpu = false;
|
|
||||||
|
|
||||||
if (IsGpuPow2Allowed)
|
if (allowGpuBatch && IsGpuPow2Allowed)
|
||||||
{
|
{
|
||||||
attemptedGpu = true;
|
|
||||||
if (batchSize <= StackGpuBatchSize)
|
if (batchSize <= StackGpuBatchSize)
|
||||||
{
|
{
|
||||||
Span<ulong> localRemainders = stackGpuRemainders.Slice(0, batchSize);
|
Span<ulong> localRemainders = stackGpuRemainders.Slice(0, batchSize);
|
||||||
@@ -499,14 +496,11 @@ internal static partial class PrimeOrderCalculator
|
|||||||
gpuPool = null;
|
gpuPool = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (attemptedGpu && !gpuSuccess)
|
if (!gpuSuccess && (status == GpuPow2ModStatus.Overflow || status == GpuPow2ModStatus.Unavailable))
|
||||||
{
|
{
|
||||||
PrimeOrderGpuHeuristics.ReportPow2Failure(
|
allowGpuBatch = false;
|
||||||
"prime order candidate scan",
|
}
|
||||||
prime,
|
|
||||||
status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < batchSize && powUsed < powBudget; i++)
|
for (int i = 0; i < batchSize && powUsed < powBudget; i++)
|
||||||
@@ -786,11 +780,6 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
return remainder == 1UL;
|
return remainder == 1UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimeOrderGpuHeuristics.ReportPow2Failure(
|
|
||||||
"prime order pow2 check",
|
|
||||||
prime,
|
|
||||||
status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return exponent.Pow2MontgomeryModWindowed(divisorData, keepMontgomery: false) == 1UL;
|
return exponent.Pow2MontgomeryModWindowed(divisorData, keepMontgomery: false) == 1UL;
|
||||||
|
|||||||
Reference in new issue
Block a user