DivisorSet scans added as EnumDependentTemplate to MersenneNumberDivisorByDivisorCpuTesterWithTemplate. New Pow2Groups scan implemented based on statistics for high divisors. MersenneNumberDivisorByDivisorPrimeScan sessions integrated into MersenneNumberDivisorByDivisorPrimeScanSessionWithTemplate. Various micro optimizations to eliminate variable, unnecessary struct creations and continue scans in higher divisor ranges, when lower ranges are exhausted. --bydivisor-k-increment command-line argument added.

This commit is contained in:
mlemanczyk committed 2025-12-28 00:45:08 +01:00
1 parent 759614de54
commit 87a66e4eca
13 files changed
+2539 -496

No files matched your search

@@ -2,6 +2,7 @@ using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using Open.Numeric.Primes;
using PerfectNumbers.Core;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
namespace EvenPerfectBitScanner.Benchmarks;
@@ -18,6 +19,8 @@ public class PrimeTesterBenchmarks
[GlobalSetup]
public void GlobalSetup()
{
EnvironmentConfiguration.RollingAccelerators = 1;
_candidates = BenchmarkCase.Candidates;
if (_candidates.Length == 0)
@@ -25,7 +28,6 @@ public class PrimeTesterBenchmarks
return;
}
EnvironmentConfiguration.RollingAccelerators = 1;
PrimeOrderCalculatorAccelerator.WarmUp();
// HeuristicGroupABPrimeTesterAccelerator.WarmUp();
+87 -40
View File
@@ -5,8 +5,8 @@ using PerfectNumbers.Core.Gpu;
namespace EvenPerfectBitScanner;
internal readonly struct CliArguments
{
internal readonly struct CliArguments
{
private const string DefaultCyclesPath = "divisor_cycles.bin";
internal readonly ulong StartPrime;
@@ -24,8 +24,10 @@ internal readonly struct CliArguments
internal readonly bool UseLucas;
internal readonly bool UseResidue;
internal readonly bool UseDivisor;
internal readonly bool UseByDivisor;
internal readonly bool UseGcdFilter;
internal readonly bool UseByDivisor;
internal readonly bool UseDivisorPow2Increment;
internal readonly int ByDivisorSpecialRange;
internal readonly bool UseGcdFilter;
internal readonly bool TestMode;
internal readonly bool UseGpuCycles;
internal readonly ComputationDevice MersenneDevice;
@@ -72,6 +74,8 @@ internal readonly struct CliArguments
bool useDivisor,
bool useByDivisor,
bool useGcdFilter,
bool useDivisorPow2Increment,
int byDivisorSpecialRange,
bool testMode,
bool useGpuCycles,
ComputationDevice mersenneDevice,
@@ -116,6 +120,8 @@ internal readonly struct CliArguments
UseResidue = useResidue;
UseDivisor = useDivisor;
UseByDivisor = useByDivisor;
UseDivisorPow2Increment = useDivisorPow2Increment;
ByDivisorSpecialRange = byDivisorSpecialRange;
UseGcdFilter = useGcdFilter;
TestMode = testMode;
UseGpuCycles = useGpuCycles;
@@ -166,6 +172,8 @@ internal readonly struct CliArguments
bool useResidue = false;
bool useDivisor = false;
bool useByDivisor = false;
bool useDivisorPow2Increment = false;
int byDivisorSpecialRange = 0;
bool useGcdFilter = false;
bool testMode = false;
bool useGpuCycles = true;
@@ -293,6 +301,41 @@ internal readonly struct CliArguments
continue;
}
if (argument.StartsWith("--bydivisor-k-increment=", StringComparison.OrdinalIgnoreCase))
{
string value = argument["--bydivisor-k-increment=".Length..].Trim();
if (value.Equals("pow2groups", StringComparison.OrdinalIgnoreCase))
{
useDivisorPow2Increment = true;
}
else if (value.Equals("sequential", StringComparison.OrdinalIgnoreCase))
{
useDivisorPow2Increment = false;
}
else
{
Console.WriteLine("Invalid value for --bydivisor-k-increment. Use onebyone or pow2groups.");
return default;
}
continue;
}
if (argument.StartsWith("--bydivisor-special-range=", StringComparison.OrdinalIgnoreCase))
{
if (Utf8CliParser.TryParseInt32(argument.AsSpan("--bydivisor-special-range=".Length), out int parsedRange) && parsedRange >= 0)
{
byDivisorSpecialRange = parsedRange;
}
else
{
Console.WriteLine("Invalid value for --bydivisor-special-range. Use a non-negative integer.");
return default;
}
continue;
}
if (argument.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
{
if (Utf8CliParser.TryParseUInt64(argument.AsSpan("--divisor-cycles-limit=".Length), out ulong parsedLimit))
@@ -576,10 +619,10 @@ internal readonly struct CliArguments
}
return new CliArguments(
startPrime,
startPrimeProvided,
maxPrimeLimit,
maxPrimeConfigured,
startPrime,
startPrimeProvided,
maxPrimeLimit,
maxPrimeConfigured,
threadCount,
blockSize,
gpuPrimeThreads,
@@ -589,37 +632,39 @@ internal readonly struct CliArguments
showHelp,
useBitTransform,
useLucas,
useResidue,
useDivisor,
useByDivisor,
useGcdFilter,
testMode,
useGpuCycles,
mersenneDevice,
orderDevice,
scanBatchSize,
sliceSize,
residueKMax,
filterFile,
forcePrimeKernelsOnCpu,
modReductionMode,
nttBackend,
resultsDirectory,
resultsPrefix,
writeBatchSize,
cyclesPath,
continueCyclesGeneration,
cyclesBatchSize,
divisorCyclesSearchLimit,
orderWarmupLimitOverride,
rleBlacklistPath,
rleHardMaxP,
rleOnlyLast7,
zeroFractionHard,
zeroFractionConjecture,
maxZeroConjecture,
minK,
gpuRatio);
useResidue,
useDivisor,
useByDivisor,
useGcdFilter,
useDivisorPow2Increment,
byDivisorSpecialRange,
testMode,
useGpuCycles,
mersenneDevice,
orderDevice,
scanBatchSize,
sliceSize,
residueKMax,
filterFile,
forcePrimeKernelsOnCpu,
modReductionMode,
nttBackend,
resultsDirectory,
resultsPrefix,
writeBatchSize,
cyclesPath,
continueCyclesGeneration,
cyclesBatchSize,
divisorCyclesSearchLimit,
orderWarmupLimitOverride,
rleBlacklistPath,
rleHardMaxP,
rleOnlyLast7,
zeroFractionHard,
zeroFractionConjecture,
maxZeroConjecture,
minK,
gpuRatio);
}
internal static void PrintHelp()
@@ -632,7 +677,9 @@ internal readonly struct CliArguments
Console.WriteLine(" --max-prime=<value> inclusive upper bound for primes from filter files");
Console.WriteLine(" --increment=bit|add exponent increment method (default add)");
Console.WriteLine(" --threads=<value> number of worker threads");
Console.WriteLine(" --mersenne=pow2mod|incremental|lucas|residue|divisor|bydivisor Mersenne test method");
S Console.WriteLine(" --mersenne=pow2mod|incremental|lucas|residue|divisor|bydivisor Mersenne test method");
Console.WriteLine(" --bydivisor-k-increment=sequential|pow2groups k iteration strategy for --mersenne=bydivisor (default sequential)");
Console.WriteLine(" --bydivisor-special-range=<n> widen pow2groups special values to +/- n percent (default 0 = points)");
Console.WriteLine(" --residue-max-k=<value> max k for residue Mersenne test (q = 2*p*k + 1)");
Console.WriteLine(" --mersenne-device=cpu|gpu|hybrid Device for Mersenne method (default gpu)");
Console.WriteLine(" --primes-device=cpu|gpu device for prime-scan kernels (default gpu)");
+138 -45
View File
@@ -8,6 +8,13 @@ using PerfectNumbers.Core;
using PerfectNumbers.Core.Cpu;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
using MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForCpuOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForHybridOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForGpuOrder;
using ByDivisorCpuOrderPow2 = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForCpuOrder;
using ByDivisorHybridOrderPow2 = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForHybridOrder;
using ByDivisorGpuOrderPow2 = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForGpuOrder;
using System.Globalization;
namespace EvenPerfectBitScanner;
@@ -21,6 +28,9 @@ private static ThreadLocal<object>? MersenneTesters;
private static MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder _byDivisorCpuOrderTester;
private static MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder _byDivisorHybridOrderTester;
private static MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder _byDivisorGpuOrderTester;
private static ByDivisorCpuOrderPow2 _byDivisorCpuOrderTesterPow2;
private static ByDivisorHybridOrderPow2 _byDivisorHybridOrderTesterPow2;
private static ByDivisorGpuOrderPow2 _byDivisorGpuOrderTesterPow2;
private static Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? _byDivisorPreviousResults;
private static bool _limitReached;
private static ulong _byDivisorStartPrime;
@@ -56,16 +66,18 @@ private static ThreadLocal<object>? MersenneTesters;
return;
}
Console.WriteLine("Initializing");
int gpuPrimeThreads = Math.Max(1, _cliArguments.GpuPrimeThreads);
int threadCount = Math.Max(1, _cliArguments.ThreadCount);
Console.WriteLine("Initializing");
int gpuPrimeThreads = Math.Max(1, _cliArguments.GpuPrimeThreads);
int threadCount = Math.Max(1, _cliArguments.ThreadCount);
EnvironmentConfiguration.MinK = _cliArguments.MinK;
EnvironmentConfiguration.GpuBatchSize = Math.Max(1, _cliArguments.ScanBatchSize);
EnvironmentConfiguration.GpuRatio = _cliArguments.GpuRatio;
EnvironmentConfiguration.OrderDevice = _cliArguments.OrderDevice;
EnvironmentConfiguration.RollingAccelerators = Math.Min(Math.Min(PerfectNumberConstants.RollingAccelerators, gpuPrimeThreads), threadCount);
EnvironmentConfiguration.Initialize();
EnvironmentConfiguration.MinK = _cliArguments.MinK;
EnvironmentConfiguration.GpuBatchSize = Math.Max(1, _cliArguments.ScanBatchSize);
EnvironmentConfiguration.GpuRatio = _cliArguments.GpuRatio;
EnvironmentConfiguration.OrderDevice = _cliArguments.OrderDevice;
EnvironmentConfiguration.UsePow2GroupDivisors = _cliArguments.UseDivisorPow2Increment;
EnvironmentConfiguration.ByDivisorSpecialRange = _cliArguments.ByDivisorSpecialRange;
EnvironmentConfiguration.RollingAccelerators = Math.Min(Math.Min(PerfectNumberConstants.RollingAccelerators, gpuPrimeThreads), threadCount);
EnvironmentConfiguration.Initialize();
// NttGpuMath.GpuTransformBackend = _cliArguments.NttBackend;
// NttGpuMath.ReductionMode = _cliArguments.ModReductionMode;
@@ -257,17 +269,39 @@ private static ThreadLocal<object>? MersenneTesters;
throw new NotSupportedException("--mersenne-device=gpu is not supported for --mersenne=bydivisor on this execution path.");
}
bool usePow2Divisors = _cliArguments.UseDivisorPow2Increment;
if (EnvironmentConfiguration.UseCpuOrder)
{
_byDivisorCpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder();
if (usePow2Divisors)
{
_byDivisorCpuOrderTesterPow2 = new ByDivisorCpuOrderPow2();
}
else
{
_byDivisorCpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder();
}
}
else if (EnvironmentConfiguration.UseHybridOrder)
{
_byDivisorHybridOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder();
if (usePow2Divisors)
{
_byDivisorHybridOrderTesterPow2 = new ByDivisorHybridOrderPow2();
}
else
{
_byDivisorHybridOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder();
}
}
else
{
_byDivisorGpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder();
if (usePow2Divisors)
{
_byDivisorGpuOrderTesterPow2 = new ByDivisorGpuOrderPow2();
}
else
{
_byDivisorGpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder();
}
}
}
@@ -483,44 +517,96 @@ private static ThreadLocal<object>? MersenneTesters;
if (useByDivisor)
{
int byDivisorPrimeRange = Math.Max(1, _cliArguments.BlockSize);
bool usePow2Divisors = _cliArguments.UseDivisorPow2Increment;
if (EnvironmentConfiguration.UseCpuOrder)
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorCpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
if (usePow2Divisors)
{
Console.WriteLine("Using by-divisor pow2groups increment (CPU order).");
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorCpuOrderTesterPow2,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorCpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
}
else if (EnvironmentConfiguration.UseHybridOrder)
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorHybridOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
if (usePow2Divisors)
{
Console.WriteLine("Using by-divisor pow2groups increment (Hybrid order).");
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorHybridOrderTesterPow2,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorHybridOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorGpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
if (usePow2Divisors)
{
Console.WriteLine("Using by-divisor pow2groups increment (GPU order).");
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorGpuOrderTesterPow2,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorGpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
}
CalculationResultHandler.FlushBuffer();
@@ -907,17 +993,24 @@ private static ThreadLocal<object>? MersenneTesters;
if (_cliArguments.UseByDivisor)
{
// Windowed pow2mod kernel handles by-divisor scans.
bool usePow2Divisors = _cliArguments.UseDivisorPow2Increment;
if (EnvironmentConfiguration.UseCpuOrder)
{
return _byDivisorCpuOrderTester.IsPrime(p, out detailedCheck, out _);
return usePow2Divisors
? _byDivisorCpuOrderTesterPow2.IsPrime(p, out detailedCheck, out _)
: _byDivisorCpuOrderTester.IsPrime(p, out detailedCheck, out _);
}
if (EnvironmentConfiguration.UseHybridOrder)
{
return _byDivisorHybridOrderTester.IsPrime(p, out detailedCheck, out _);
return usePow2Divisors
? _byDivisorHybridOrderTesterPow2.IsPrime(p, out detailedCheck, out _)
: _byDivisorHybridOrderTester.IsPrime(p, out detailedCheck, out _);
}
return _byDivisorGpuOrderTester.IsPrime(p, out detailedCheck, out _);
return usePow2Divisors
? _byDivisorGpuOrderTesterPow2.IsPrime(p, out detailedCheck, out _)
: _byDivisorGpuOrderTester.IsPrime(p, out detailedCheck, out _);
}
detailedCheck = IsMersennePrime(gpu, p);
@@ -1,6 +1,7 @@
using System.Numerics;
using FluentAssertions;
using PerfectNumbers.Core.Cpu;
using MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForCpuOrder;
using Xunit;
namespace PerfectNumbers.Core.Tests;
@@ -8,27 +8,38 @@ namespace PerfectNumbers.Core;
/// Mirrors <see cref="CycleRemainderStepper"/> for values that exceed 64 bits.
/// </summary>
[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
public struct BigIntegerCycleRemainderStepper(BigInteger cycleLength)
public struct BigIntegerCycleRemainderStepper(byte cycleLength)
{
private readonly BigInteger _cycleLength = cycleLength;
private readonly BigInteger _cycleLength = (BigInteger)cycleLength;
private BigInteger _previousValue = BigInteger.Zero;
private BigInteger _currentRemainder = BigInteger.Zero;
private BigInteger _currentRemainder = 0;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public BigInteger Initialize(BigInteger value)
public byte Initialize(BigInteger value)
{
_previousValue = value;
_currentRemainder = value.ReduceCycleRemainder(_cycleLength);
return _currentRemainder;
_currentRemainder = value % _cycleLength;
return (byte)_currentRemainder;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public BigInteger ComputeNext(BigInteger value)
public bool NextIsNotDivisible(BigInteger value)
{
BigInteger delta = value - _previousValue;
BigInteger delta = value - _previousValue;
_previousValue = value;
_currentRemainder = (_currentRemainder + delta).ReduceCycleRemainder(_cycleLength);
delta = (_currentRemainder + delta) % _cycleLength;
_currentRemainder = delta;
return !delta.IsZero;
}
return _currentRemainder;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public byte ComputeNext(BigInteger value)
{
BigInteger delta = value - _previousValue;
_previousValue = value;
delta = (_currentRemainder + delta) % _cycleLength;
_currentRemainder = delta;
return (byte)delta;
}
}
@@ -0,0 +1,185 @@
#define DIVISOR_SPECIALIZED
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PerfectNumbers.Core.Cpu;
public static class DivisorByDivisorConfig
{
#if DIVISOR_SPECIALIZED
public const int PercentScale = 10_000;
public static readonly (int Start, int End)[] PercentGroupsPromille =
[
(9998, 10000),
(9844, 9845),
(9561, 9562),
(9402, 9403),
(9307, 9308),
(9127, 9128),
(8900, 8901),
(8682, 8683),
(8546, 8547),
(8381, 8382),
(7988, 7989),
(7693, 7694),
(7426, 7427),
(7184, 7185),
(6705, 6706),
(6473, 6474),
(6218, 6219),
(5944, 5945),
(5791, 5792),
(5530, 5531),
(4902, 4903),
(4657, 4658),
(4388, 4389),
(4119, 4120),
(3844, 3845),
(3602, 3603),
(3477, 3478),
(3112, 3113),
(2901, 2902),
(2742, 2743),
(2358, 2359),
(2134, 2135),
(1827, 1828),
(1611, 1612),
(1439, 1440),
(1354, 1355),
(1281, 1284),
(0906, 0907),
(0847, 0848),
(0706, 0707),
(0694, 0695),
(0569, 0570),
(0244, 0245),
(0204, 0205),
(0143, 0144),
(0095, 0096),
(0070, 0071),
];
public static readonly int[] SpecialPercentPromille = [
0070,
0143,
0095,
0204,
0244,
0569,
0694,
0706,
0847,
0906,
0955,
0958,
1060,
1018,
1132,
1308,
1416,
1782,
1875,
2026,
2349,
2451,
2464,
2782,
3065,
3088,
3113,
3257,
3284,
3304,
3318,
3343,
3351,
3383,
3431,
3566,
3617,
3938,
3985,
3994,
4053,
4166,
4248,
4337,
4344,
4467,
4493,
4866,
5043,
5189,
5208,
5510,
5530,
5925,
6198,
6281,
6324,
6363,
6366,
6387,
6474,
6477,
6546,
6548,
6729,
6741,
6841,
7203,
7211,
7234,
7589,
7593,
7664,
7775,
8076,
8203,
8273,
8331,
8381,
8546,
8682,
8900,
9127,
9307,
9402,
9561,
9844,
9998,
1000,
];
#elif DIVISOR_SPECIALIZED_LOW_DIVISORS
public const int PercentScale = 10_000;
public static readonly (int Start, int End)[] PercentGroupsPromille =
[
(4500, 5500),
(7000, 8000),
(9500, 9800),
(9800, 10000),
(3000, 4500),
(0, 1000),
];
public static readonly int[] SpecialPercentPromille = [9840, 10000, 7500, 5000, 3910, 0292, 0297, 0325, 0354, 0314, 0339, 0337, 0316, 0341, 0352, 0351, 0283, 0313, 0330, 0301, 0348, 0298, 0290, 0335, 0309, 0322, 0321, 0312, 0323, 0303, 0349, 0344, 0327, 0295, 0299, 0320, 0285, 0306, 0310, 0287, 0332, 0340, 0293, 0317, 0305, 0342, 0311, 0318, 0346, 0294, 0350, 0284, 0308, 0307, 0286, 0324, 0353, 0336, 0288, 0291, 0334, 0326, 0355, 0356, 0319, 0300, 0338, 0331, 0333, 0302, 0304, 0328, 0345, 0347, 0315, 0343, 0289, 0296, 0329, 5444, 0282, 5426, 5424, 5443, 5434, 5470, 5430, 5528, 5517, 5464, 5484, 5495, 5428, 5427, 5505, 5425, 5454, 5521, 5497, 5501, 5461, 5436, 5468, 5490, 5508, 5515, 5456, 5437, 5438, 5448, 5479, 5524, 5500, 5446, 5473, 5486, 5531, 5472, 5469, 5463, 5460, 5485, 5502, 5519, 5489, 5518, 5442, 5510, 5487, 5482, 5493, 5471, 5522, 5514, 1631, 5496, 1639, 5520, 1649, 5527, 5498, 5530, 5440, 5534, 5532, 5433, 5480, 5488, 5511, 5529, 5492, 5465, 5504, 5445, 5491, 1643, 5476, 5432, 5449, 5439, 5512, 5478, 5525, 1622, 5506, 5523, 5474, 5451, 5467, 5457, 5431, 5452, 5481, 1568, 1610, 5450, 1587, 1572, 1603, 5507, 1641, 1635, 5441, 5509, 5429, 5494, 5475, 5458, 5483, 5526, 5513, 1611, 1605, 1602, 1594, 5459, 1623, 1577, 1638, 1613, 1573, 6754, 1599, 1644, 3532, 1570, 5435, 1647, 7999, 1618, 1616, 3582, 5453, 4236, 1604, 1640, 1608, 3572, 1645, 1578, 1588, 5466, 8120, 1607, 1632, 1569, 1646, 8045, 9326, 1637, 3531, 3510, 1571, 5499, 1600, 1597, 8081, 3559, 0191, 5533, 5447, 9390, 1634, 8025, 9308, 1574, 0951, 1586, 4149, 1583, 8103, 2762, 5477, 8115, 5924, 1576, 1619, 8019, 3504, 2908, 1591, 0628, 5503, 1592, 2877, 3521, 1617, 0618, 2927, 8069, 0942, 1584, 2853, 3574, 8119, 1595, 0647, 2294, 1620, 0274, 1255, 1899, 1596, 8071, 2864, 1590, 3900, 2939, 1135, 9319, 1502, 1475, 8021, 0950, 0027, 8056, 1630, 0988, 7440, 0962, 3579, 9340, 9285, 2562, 3002, 8039, 1589, 4154, 8005, 4205, 6755, 9320, 4189, 9301, 4216, 9282, 4167, 8033, 1606, 3577, 3571, 8092, 5462, 1314, 5516, 3501, 2945, 3034, 0646, 3535, 1257, 0958, 1612, 1001, 1651, 1648, 8051, 1626, 8067, 1601, 7406, 3589, 4219, 4074, 9295, 1120, 2867, 9313, 2250, 2882, 7415, 9291, 3512, 4171, 9304, 8653, 1615, 2905, 8068, 9370, 4218, 1258, 5455, 8090, 3190, 0960, 7362, 8063, 1642, 9335, 9343, 9401, 9310, 2402, 9318, 8048, 9374, 3526, 9325, 3152, 8052, 2895, 5847, 3546, 1081, 9280, 2233, 1628, 6790, 2854, 4203, 9322, 4200, 0001, 6774, 4459, 7994, 6822, 1650, 3585, 3395, 1625, 3207, 6770, 4204, 2890, 8055, 9346, 0522, 4191, 9352, 0021, 8696, 3498, 6803, 9345, 3426, 7442, 3541, 9405, 9384, 0984, 2866, 3220, 0249, 0625, 1751, 2920, 2916, 0965, 2851, 7473, 9336, 9380, 2565, 0517, 2249, 4161, 0012, 0640, 9373, 1271, 8113, 2253, 2938, 2925, 4827, 0636, 1636, 3563, 2260, 0642, 0928, 1627, 3547, 2865, 8020, 1579, 9297, 0983, 9377, 0837, 8376, 0968, 0635, 1593, 3565, 9395, 8078, 0262, 0442, 0785, 2076, 9415, 3079, 9366, 1581, 0931, 8118, 8034, 8004, 4175, 5282, 1790, 7998, 3209, 2052, 9391, 0970, 0156, 0934, 4211, 9410, 9383, 7446, 2961, 0121, 3583, 1299, 4797, 2102, 2926, 4978, 8111, 7418, 9375, 9372, 7401, 1909, 6736, 0243, 2210, 8035, 3558, 9353, 9356, 9357, 3025, 9368, 1324, 2440, 6798, 2080, 2270, 2742, 1152, 4796, 8080, 0124, 6752, 8123, 6727, 2374, 3684, 9414, 0648, 1580, 2817, 5753, 1318, 0641, 6737, 2269, 2911, 8341, 6807, 9341, 6468, 9398, 1614, 4150, 8029, 9315, 2683, 2457, 3502, 6761, 3539, 4176, 2618, 1973, 2947, 3047, 9329, 9351, 8102, 6414, 8093, 1294, 0622, 0969, 2078, 2934, 4422, 2165, 3036, 8084, 0164, 0664, 0456, 6777, 6808, 4863, 3217, 3529, 4385, 5733, 2915, 9358, 3499, 2786, 0981, 5194, 3561, 1964, 2544, 0766, 8022, 1090, 7508, 5780, 0775, 2085, 8018, 3540, 7366, 1598, 4170, 5307, 0671, 3511, 1624, 9416, 3021, 0952, 3580, 3073, 5953, 1371, 8044, 4477, 0992, 0652, 9359, 0957, 8392, 3588, 4213, 4141, 9364, 1871, 3367, 8700, 4916, 8013, 5043, 4057, 7126, 1945, 3174, 3562, 0093, 3537, 3096, 0659, 7394, 0630, 3509, 5619, 2310, 0814, 1471, 0609, 8038, 1268, 0666, 0023, 3587, 4138, 0935, 4786, 8076, 9393, 9404, 6235, 1290, 0224, 2955, 0547, 8121, 4857, 4838, 2880, 1330, 6758, 3748, 2421, 0038, 8001, 6744, 7785, 0658, 6158, 8032, 1957, 0166, 0989, 1156, 0947, 2448, 3065, 2935, 2442, 2697, 6805, 6826, 3523, 7384, 2940, 1686, 2235, 1609, 8697, 3039, 4181, 2064, 4563, 1437, 1115, 0939, 5207, 4826, 8098, 0364, 3522, 9363, 0660, 2869, 4144, 1750, 8673, 1121, 2770, 7359, 2910, 9947, 0528, 0967, 3763, 9075, 3260, 5779, 1935, 1237, 1582, 2518, 0819, 3518, 1286, 1295, 0644, 1377, 8091, 3473, 8083, 9417, 2323, 1124, 0069, 0973, 0409, 0842, 0674, 6728, 4803, 0035, 1575, 2057, 2932, 2888, 9348, 4185, 8027, 3624, 0982, 1806, 1907, 8638, 4160, 0729, 1709, 8495, 4212, 0926, 8108, 1106, 6731, 0424, 8100, 1254, 5877, 2244, 5181, 2859, 1758, 2071, 3497, 2285, 4187, 5595, 3576, 2236, 9412, 6472, 6453, 6719, 3862, 4220, 4184, 2781, 8766, 4022, 2839, 6434, 1493, 0611, 9289, 5596, 2861, 6743, 8031, 1972, 8023, 8053, 0138, 4880, 2259, 4230, 2893, 2937, 9333, 3292, 7206, 5200Line truncated
#else
public const int PercentScale = 100_000;
public static readonly (int Start, int End)[] PercentGroupsPromille =
[
(45000, 55000),
(70000, 80000),
(95000, 98000),
(98000, 100000),
(30000, 45000),
(0, 10000),
];
public static readonly int[] SpecialPercentPromille = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 10Line truncated
#endif
}
File diff suppressed because it is too large. Load diff
@@ -1,88 +0,0 @@
using System.Globalization;
using System.Numerics;
using PerfectNumbers.Core.Gpu;
namespace PerfectNumbers.Core.Cpu;
internal struct MersenneNumberDivisorByDivisorPrimeScanSessionWithCpuOrder(
in MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder prototype,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult)
{
private MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder _tester = new()
{
DivisorLimit = prototype.DivisorLimit,
MinK = EnvironmentConfiguration.MinK,
};
private MersenneCpuDivisorScanSessionWithCpuOrder _divisorScanSession = new();
private readonly Action _markComposite = markComposite;
private readonly Action _clearComposite = clearComposite;
private readonly Action<ulong, bool, bool, bool, BigInteger> _printResult = printResult;
public void ProcessPrime(ulong prime)
{
try
{
Console.WriteLine($"Processing {prime}");
string stateFile = Path.Combine(
PerfectNumberConstants.ByDivisorStateDirectory,
prime.ToString(CultureInfo.InvariantCulture) + ".bin");
ConfigureForPrime(stateFile);
bool isPrime = _tester.IsPrime(prime, out bool divisorsExhausted, out BigInteger divisor);
if (!isPrime)
{
if (!string.IsNullOrEmpty(stateFile) && File.Exists(stateFile))
{
File.Delete(stateFile);
}
_markComposite();
_printResult(prime, true, true, false, divisor);
Console.WriteLine($"Finished processing {prime}");
return;
}
_clearComposite();
_printResult(prime, true, divisorsExhausted, true, divisor);
Console.WriteLine($"Finished processing {prime}");
}
catch (Exception ex)
{
Console.WriteLine($"Error processing {ex.Message} {ex.StackTrace}");
Environment.Exit(1);
}
}
private void ConfigureForPrime(string stateFile)
{
BigInteger resumeK = EnvironmentConfiguration.MinK;
if (File.Exists(stateFile))
{
if (MersenneNumberDivisorByDivisorTester.TryReadLastSavedK(stateFile, out BigInteger lastK))
{
resumeK = lastK + BigInteger.One;
_tester.ResumeFromState(stateFile, lastK, resumeK);
}
else
{
_tester.ResumeFromState(stateFile, BigInteger.Zero, resumeK);
}
}
else
{
_tester.ResumeFromState(stateFile, BigInteger.Zero, resumeK);
}
_tester.ResetStateTracking();
}
public void Dispose()
{
}
}
@@ -1,101 +0,0 @@
using System.Globalization;
using System.Numerics;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
namespace PerfectNumbers.Core.Cpu;
internal struct MersenneNumberDivisorByDivisorPrimeScanSessionWithHybridOrder
{
private MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder _tester;
private MersenneCpuDivisorScanSessionWithHybridOrder _divisorScanSession;
private readonly Action _markComposite;
private readonly Action _clearComposite;
private readonly Action<ulong, bool, bool, bool, BigInteger> _printResult;
public MersenneNumberDivisorByDivisorPrimeScanSessionWithHybridOrder(
in MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder prototype,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult)
{
_tester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder
{
DivisorLimit = prototype.DivisorLimit,
MinK = EnvironmentConfiguration.MinK,
};
_divisorScanSession = new MersenneCpuDivisorScanSessionWithHybridOrder();
_divisorScanSession.Configure(_tester.Accelerator);
_markComposite = markComposite;
_clearComposite = clearComposite;
_printResult = printResult;
}
public void ProcessPrime(ulong prime)
{
try
{
Console.WriteLine($"Processing {prime}");
string stateFile = Path.Combine(
PerfectNumberConstants.ByDivisorStateDirectory,
prime.ToString(CultureInfo.InvariantCulture) + ".bin");
ConfigureForPrime(stateFile);
bool isPrime = _tester.IsPrime(prime, out bool divisorsExhausted, out BigInteger divisor);
if (!isPrime)
{
if (!string.IsNullOrEmpty(stateFile) && File.Exists(stateFile))
{
File.Delete(stateFile);
}
_markComposite();
_printResult(prime, true, true, false, divisor);
Console.WriteLine($"Finished processing {prime}");
return;
}
_clearComposite();
_printResult(prime, true, divisorsExhausted, true, divisor);
Console.WriteLine($"Finished processing {prime}");
}
catch (Exception ex)
{
Console.WriteLine($"Error processing {ex.Message} {ex.StackTrace}");
Environment.Exit(1);
}
}
private void ConfigureForPrime(string stateFile)
{
BigInteger resumeK = EnvironmentConfiguration.MinK;
if (File.Exists(stateFile))
{
if (MersenneNumberDivisorByDivisorTester.TryReadLastSavedK(stateFile, out BigInteger lastK))
{
resumeK = lastK + BigInteger.One;
_tester.ResumeFromState(stateFile, lastK, resumeK);
}
else
{
_tester.ResumeFromState(stateFile, BigInteger.Zero, resumeK);
}
}
else
{
_tester.ResumeFromState(stateFile, BigInteger.Zero, resumeK);
}
_tester.ResetStateTracking();
}
public void Dispose()
{
PrimeOrderCalculatorAccelerator.Return(_tester.Accelerator);
}
}
@@ -1,34 +1,59 @@
using System.Globalization;
using System.Globalization;
using System.IO;
using System.Numerics;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
using System.Runtime.CompilerServices;
#if DivisorSet_Pow2Groups
using TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForCpuOrder;
using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForHybridOrder;
using TesterGpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForGpuOrder;
#else
using TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForCpuOrder;
using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForHybridOrder;
using TesterGpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForGpuOrder;
#endif
namespace PerfectNumbers.Core.Cpu;
internal struct MersenneNumberDivisorByDivisorPrimeScanSessionWithGpuOrder
[EnumDependentTemplate(typeof(DivisorSet))]
[DeviceDependentTemplate(typeof(ComputationDevice))]
[NameSuffix("Order")]
internal struct MersenneNumberDivisorByDivisorPrimeScanSessionWithTemplate
{
private MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder _tester;
private MersenneCpuDivisorScanSessionWithGpuOrder _divisorScanSession;
#if DEVICE_GPU
private TesterGpu _tester;
#elif DEVICE_HYBRID
private TesterHybrid _tester;
#else
private TesterCpu _tester;
#endif
private readonly Action _markComposite;
private readonly Action _clearComposite;
private readonly Action<ulong, bool, bool, bool, BigInteger> _printResult;
public MersenneNumberDivisorByDivisorPrimeScanSessionWithGpuOrder(
in MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder prototype,
public MersenneNumberDivisorByDivisorPrimeScanSessionWithTemplate(
#if DEVICE_GPU
in TesterGpu prototype,
#elif DEVICE_HYBRID
in TesterHybrid prototype,
#else
in TesterCpu prototype,
#endif
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult)
{
_tester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder
_tester = new()
{
DivisorLimit = prototype.DivisorLimit,
MinK = EnvironmentConfiguration.MinK,
};
_divisorScanSession = new MersenneCpuDivisorScanSessionWithGpuOrder();
_divisorScanSession.Configure(_tester.Accelerator);
_markComposite = markComposite;
_clearComposite = clearComposite;
_printResult = printResult;
@@ -94,8 +119,11 @@ internal struct MersenneNumberDivisorByDivisorPrimeScanSessionWithGpuOrder
_tester.ResetStateTracking();
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void Dispose()
{
#if DEVICE_GPU || DEVICE_HYBRID
PrimeOrderCalculatorAccelerator.Return(_tester.Accelerator);
#endif
}
}
@@ -18,6 +18,8 @@ public static class EnvironmentConfiguration
public static bool UseGpuOrder;
public static bool UseHybridOrder;
public static bool UseCpuOrder;
public static bool UsePow2GroupDivisors;
public static int ByDivisorSpecialRange;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Initialize()
@@ -6,6 +6,9 @@ using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
using PerfectNumbers.Core.Cpu;
using System.Runtime.CompilerServices;
using MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForCpuOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForHybridOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForGpuOrder;
namespace PerfectNumbers.Core;
@@ -104,6 +107,99 @@ public static class MersenneNumberDivisorByDivisorTester
Action<ulong, bool, bool, bool, BigInteger> pr) =>
RunGpuOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Run(
List<ulong> candidates,
ref MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForCpuOrder tester,
Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? previousResults,
ulong startPrime,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult,
int threadCount,
int primesPerTask)
=> RunStructTester(
candidates,
ref tester,
previousResults,
startPrime,
markComposite,
clearComposite,
printResult,
threadCount,
primesPerTask,
static (
List<ulong> filteredPrimes,
in MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForCpuOrder prototype,
int workerCount,
int partitionSize,
Action mc,
Action cc,
Action<ulong, bool, bool, bool, BigInteger> pr) =>
RunCpuOrderFilteredPow2(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Run(
List<ulong> candidates,
ref MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForHybridOrder tester,
Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? previousResults,
ulong startPrime,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult,
int threadCount,
int primesPerTask)
=> RunStructTester(
candidates,
ref tester,
previousResults,
startPrime,
markComposite,
clearComposite,
printResult,
threadCount,
primesPerTask,
static (
List<ulong> filteredPrimes,
in MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForHybridOrder prototype,
int workerCount,
int partitionSize,
Action mc,
Action cc,
Action<ulong, bool, bool, bool, BigInteger> pr) =>
RunHybridOrderFilteredPow2(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Run(
List<ulong> candidates,
ref MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForGpuOrder tester,
Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? previousResults,
ulong startPrime,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult,
int threadCount,
int primesPerTask)
=> RunStructTester(
candidates,
ref tester,
previousResults,
startPrime,
markComposite,
clearComposite,
printResult,
threadCount,
primesPerTask,
static (
List<ulong> filteredPrimes,
in MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForGpuOrder prototype,
int workerCount,
int partitionSize,
Action mc,
Action cc,
Action<ulong, bool, bool, bool, BigInteger> pr) =>
RunGpuOrderFilteredPow2(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
internal static bool TryReadLastSavedK(string stateFile, out BigInteger lastSavedK)
{
lastSavedK = BigInteger.Zero;
@@ -224,7 +320,7 @@ public static class MersenneNumberDivisorByDivisorTester
if (maxPrime - 1UL >= 64UL)
{
return (BigInteger.One << 256) - BigInteger.One;
return BigIntegerNumbers.OneShiftedLeft256MinusOne;
}
return (BigInteger.One << (int)(maxPrime - 1UL)) - BigInteger.One;
@@ -901,7 +997,7 @@ public static class MersenneNumberDivisorByDivisorTester
if (workerCount == 1)
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForOneByOneDivisorSetForCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
foreach (ulong prime in filteredPrimes)
{
session.ProcessPrime(prime);
@@ -923,7 +1019,7 @@ public static class MersenneNumberDivisorByDivisorTester
() =>
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForOneByOneDivisorSetForCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
startGate.Wait();
Console.WriteLine($"Task started for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
@@ -986,7 +1082,7 @@ public static class MersenneNumberDivisorByDivisorTester
if (workerCount == 1)
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForOneByOneDivisorSetForHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
GpuPrimeWorkLimiter.Acquire();
foreach (ulong prime in filteredPrimes)
@@ -1012,7 +1108,7 @@ public static class MersenneNumberDivisorByDivisorTester
() =>
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForOneByOneDivisorSetForHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
startGate.Wait();
Console.WriteLine($"Task started for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
@@ -1077,7 +1173,7 @@ public static class MersenneNumberDivisorByDivisorTester
if (workerCount == 1)
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForOneByOneDivisorSetForGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
GpuPrimeWorkLimiter.Acquire();
foreach (ulong prime in filteredPrimes)
@@ -1103,7 +1199,7 @@ public static class MersenneNumberDivisorByDivisorTester
() =>
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForOneByOneDivisorSetForGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
startGate.Wait();
Console.WriteLine($"Task started for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
@@ -1231,5 +1327,255 @@ public static class MersenneNumberDivisorByDivisorTester
Task.WaitAll(tasks);
startGate.Dispose();
}
private static void RunCpuOrderFilteredPow2(
List<ulong> filteredPrimes,
in MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForCpuOrder prototype,
int workerCount,
int partitionSize,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult)
{
MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForCpuOrder prototypeCopy = prototype;
int totalCount = filteredPrimes.Count;
if (partitionSize > totalCount)
{
partitionSize = totalCount;
}
if (workerCount == 1)
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForPow2GroupsDivisorSetForCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
foreach (ulong prime in filteredPrimes)
{
session.ProcessPrime(prime);
}
session.Dispose();
return;
}
TaskScheduler scheduler = UnboundedTaskScheduler.Instance;
int nextIndex = 0;
Task[] tasks = new Task[workerCount];
var startGate = new ManualResetEventSlim(initialState: false);
for (int taskIndex = 0; taskIndex < workerCount; taskIndex++)
{
int workerIndex = taskIndex;
tasks[taskIndex] = Task.Factory.StartNew(
() =>
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForPow2GroupsDivisorSetForCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
startGate.Wait();
Console.WriteLine($"Task started for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
while (true)
{
int start = Interlocked.Add(ref nextIndex, partitionSize) - partitionSize;
if (start >= totalCount)
{
break;
}
int end = start + partitionSize;
if (end > totalCount)
{
end = totalCount;
}
for (int index = start; index < end; index++)
{
ulong prime = filteredPrimes[index];
if (prime > 1)
{
session.ProcessPrime(prime);
}
}
}
session.Dispose();
Console.WriteLine($"Task finished for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
},
CancellationToken.None,
TaskCreationOptions.None,
scheduler);
}
startGate.Set();
Console.WriteLine("All tasks started");
for (int index = 0; index < tasks.Length; index++)
{
tasks[index].Wait();
Console.WriteLine($"Task {index.ToString(CultureInfo.InvariantCulture)} finished");
}
}
private static void RunHybridOrderFilteredPow2(
List<ulong> filteredPrimes,
in MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForHybridOrder prototype,
int workerCount,
int partitionSize,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult)
{
MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForHybridOrder prototypeCopy = prototype;
int totalCount = filteredPrimes.Count;
if (partitionSize > totalCount)
{
partitionSize = totalCount;
}
if (workerCount == 1)
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForPow2GroupsDivisorSetForHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
foreach (ulong prime in filteredPrimes)
{
session.ProcessPrime(prime);
}
session.Dispose();
return;
}
TaskScheduler scheduler = UnboundedTaskScheduler.Instance;
int nextIndex = 0;
Task[] tasks = new Task[workerCount];
var startGate = new ManualResetEventSlim(initialState: false);
for (int taskIndex = 0; taskIndex < workerCount; taskIndex++)
{
int workerIndex = taskIndex;
tasks[taskIndex] = Task.Factory.StartNew(
() =>
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForPow2GroupsDivisorSetForHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
startGate.Wait();
Console.WriteLine($"Task started for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
while (true)
{
int start = Interlocked.Add(ref nextIndex, partitionSize) - partitionSize;
if (start >= totalCount)
{
break;
}
int end = start + partitionSize;
if (end > totalCount)
{
end = totalCount;
}
for (int index = start; index < end; index++)
{
ulong prime = filteredPrimes[index];
if (prime > 1)
{
session.ProcessPrime(prime);
}
}
}
session.Dispose();
Console.WriteLine($"Task finished for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
},
CancellationToken.None,
TaskCreationOptions.None,
scheduler);
}
startGate.Set();
for (int index = 0; index < tasks.Length; index++)
{
tasks[index].Wait();
Console.WriteLine($"Task finished {index.ToString(CultureInfo.InvariantCulture)}");
}
}
private static void RunGpuOrderFilteredPow2(
List<ulong> filteredPrimes,
in MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForGpuOrder prototype,
int workerCount,
int partitionSize,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, BigInteger> printResult)
{
MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForGpuOrder prototypeCopy = prototype;
int totalCount = filteredPrimes.Count;
if (partitionSize > totalCount)
{
partitionSize = totalCount;
}
if (workerCount == 1)
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForPow2GroupsDivisorSetForGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
foreach (ulong prime in filteredPrimes)
{
session.ProcessPrime(prime);
}
session.Dispose();
return;
}
TaskScheduler scheduler = UnboundedTaskScheduler.Instance;
int nextIndex = 0;
Task[] tasks = new Task[workerCount];
var startGate = new ManualResetEventSlim(initialState: false);
for (int taskIndex = 0; taskIndex < workerCount; taskIndex++)
{
int workerIndex = taskIndex;
tasks[taskIndex] = Task.Factory.StartNew(
() =>
{
DeterministicRandomCpu.Initialize();
var session = new MersenneNumberDivisorByDivisorPrimeScanSessionWithForPow2GroupsDivisorSetForGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
startGate.Wait();
Console.WriteLine($"Task started for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
while (true)
{
int start = Interlocked.Add(ref nextIndex, partitionSize) - partitionSize;
if (start >= totalCount)
{
break;
}
int end = start + partitionSize;
if (end > totalCount)
{
end = totalCount;
}
for (int index = start; index < end; index++)
{
ulong prime = filteredPrimes[index];
if (prime > 1)
{
session.ProcessPrime(prime);
}
}
}
session.Dispose();
Console.WriteLine($"Task finished for worker {workerIndex.ToString(CultureInfo.InvariantCulture)}");
},
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
scheduler);
}
startGate.Set();
Task.WaitAll(tasks);
startGate.Dispose();
}
}
@@ -170,20 +170,20 @@ public static partial class PrimeOrderCalculatorTemplate
private static int GetGroupWide(in UInt128 value, in UInt128 prime)
{
UInt128 threshold1 = prime >> 3;
if (value <= threshold1)
UInt128 threshold = prime >> 3;
if (value <= threshold)
{
return 1;
}
UInt128 threshold2 = prime >> 2;
if (value <= threshold2)
threshold = prime >> 2;
if (value <= threshold)
{
return 2;
}
UInt128 threshold3 = (UInt128)(((BigInteger)prime * 3) >> 3);
if (value <= threshold3)
threshold = (UInt128)(((BigInteger)prime * 3) >> 3);
if (value <= threshold)
{
return 3;
}
@@ -306,6 +306,7 @@ public static partial class PrimeOrderCalculatorTemplate
}
FactorEntry128 factor = factors[index];
index++;
UInt128 primeFactor = factor.Value;
UInt128 contribution = UInt128.One;
for (int exponent = 0; exponent <= factor.Exponent; exponent++)
@@ -316,7 +317,7 @@ public static partial class PrimeOrderCalculatorTemplate
break;
}
BuildCandidatesRecursiveWide(order, factors, index + 1, nextDivisor, candidates, limit);
BuildCandidatesRecursiveWide(order, factors, index, nextDivisor, candidates, limit);
if (candidates.Count >= limit)
{
return;
@@ -1267,48 +1268,49 @@ public static partial class PrimeOrderCalculatorTemplate
private static int ExtractSmallPrimeExponent(ref ulong value, ulong primeValue, ulong quotient)
{
ulong dividend = quotient;
int exponent = 1;
if (dividend < primeValue)
{
value = dividend;
return exponent;
return 1;
}
quotient = dividend / primeValue;
ulong product = quotient * primeValue;
if (dividend - product != 0UL)
if (dividend - quotient * primeValue != 0UL)
{
value = dividend;
return exponent;
return 1;
}
dividend = quotient;
exponent++;
if (dividend < primeValue)
{
value = dividend;
return exponent;
return 2;
}
quotient = dividend / primeValue;
product = quotient * primeValue;
if (dividend - product != 0UL)
if (dividend - quotient * primeValue != 0UL)
{
value = dividend;
return exponent;
return 2;
}
dividend = quotient;
exponent++;
return ExtractSmallPrimeExponentWithLoop(ref value, primeValue, quotient);
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int ExtractSmallPrimeExponentWithLoop(ref ulong value, ulong primeValue, ulong quotient)
{
ulong dividend = quotient;
int exponent = 3;
while (true)
{
quotient = dividend / primeValue;
product = quotient * primeValue;
if (dividend - product != 0UL)
if (dividend - quotient * primeValue != 0UL)
{
break;
}
@@ -1319,7 +1321,8 @@ public static partial class PrimeOrderCalculatorTemplate
value = dividend;
return exponent;
}
}
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
@@ -1336,16 +1339,13 @@ public static partial class PrimeOrderCalculatorTemplate
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong AdvancePolynomial(ulong x, ulong c, ulong modulus)
{
return unchecked((x * x) % modulus + c) % modulus;
}
private static ulong AdvancePolynomial(ulong x, ulong c, ulong modulus) => unchecked(x * x % modulus + c) % modulus;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong AdvancePolynomialTwice(ulong x, ulong c, ulong modulus)
{
x = AdvancePolynomial(x, c, modulus);
return AdvancePolynomial(x, c, modulus);
x = unchecked(x * x % modulus + c) % modulus;
return unchecked(x * x % modulus + c) % modulus;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
@@ -1911,14 +1911,29 @@ public static partial class PrimeOrderCalculatorTemplate
List<PartialFactorPendingEntry> pending = result.PendingFactors;
pending.Clear();
// #if DEVICE_HYBRID
// bool pollardRhoDeadlineReached = false;
// CollectSmallFactors(gpu, config, exponentSlots, primeSlots, ref value, ref pollardRhoDeadlineReached, out int factorCount);
// if (factorCount == 0 && !pollardRhoDeadlineReached)
// {
// PopulateSmallPrimeFactors(
// value,
// config.SmallFactorLimit,
// primeSlots,
// exponentSlots,
// out factorCount,
// out value);
// }
// #elif DEVICE_CPU
PopulateSmallPrimeFactors(
value,
config.SmallFactorLimit,
primeSlots,
exponentSlots,
out int factorCount,
out value);
// #endif
PopulateSmallPrimeFactors(
value,
config.SmallFactorLimit,
primeSlots,
exponentSlots,
out int factorCount,
out value);
bool cofactorContainsComposite;
if (value > 1UL)
@@ -3051,7 +3066,7 @@ public static partial class PrimeOrderCalculatorTemplate
return true;
}
#if DEVICE_GPU
#if DEVICE_GPU //|| DEVICE_HYBRID
private const int GpuSmallPrimeFactorSlots = 64;
// GPU specific. It doesn't make sense to consolidate into one method.