Merge pull request #31 from mlemanczyk/codex/modify-evenperfectbitscanner-for-uint128-divisors
Allow residue GPU scanning to cover UInt128 divisors
This commit is contained in:
6 files changed
+35
-29
No files matched your search
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Globalization;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -73,11 +74,12 @@ internal static class Program
|
|||||||
bool mersenneOnGpu = true; // controls Lucas/incremental/pow2mod device
|
bool mersenneOnGpu = true; // controls Lucas/incremental/pow2mod device
|
||||||
bool orderOnGpu = true; // controls order computations device
|
bool orderOnGpu = true; // controls order computations device
|
||||||
int scanBatchSize = 2_097_152, sliceSize = 32;
|
int scanBatchSize = 2_097_152, sliceSize = 32;
|
||||||
ulong residueKMax = 5_000_000UL;
|
UInt128 residueKMax = 5_000_000UL;
|
||||||
string filterFile = string.Empty;
|
string filterFile = string.Empty;
|
||||||
string cyclesPath = DefaultCyclesPath;
|
string cyclesPath = DefaultCyclesPath;
|
||||||
int cyclesBatchSize = 512;
|
int cyclesBatchSize = 512;
|
||||||
bool continueCyclesGeneration = false;
|
bool continueCyclesGeneration = false;
|
||||||
|
UInt128 divisorCyclesSearchLimit128 = PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
|
||||||
ulong divisorCyclesSearchLimit = PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
|
ulong divisorCyclesSearchLimit = PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
|
||||||
|
|
||||||
// NTT backend selection (GPU): reference vs staged
|
// NTT backend selection (GPU): reference vs staged
|
||||||
@@ -143,12 +145,16 @@ internal static class Program
|
|||||||
else if (arg.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
|
else if (arg.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
int eq = arg.IndexOf('=');
|
int eq = arg.IndexOf('=');
|
||||||
divisorCyclesSearchLimit = ulong.Parse(arg.AsSpan(eq + 1));
|
if (UInt128.TryParse(arg.AsSpan(eq + 1), NumberStyles.Integer, provider: null, out var limit))
|
||||||
|
{
|
||||||
|
divisorCyclesSearchLimit128 = limit;
|
||||||
|
divisorCyclesSearchLimit = limit > (UInt128)ulong.MaxValue ? ulong.MaxValue : (ulong)limit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (arg.StartsWith("--residue-max-k=", StringComparison.OrdinalIgnoreCase))
|
else if (arg.StartsWith("--residue-max-k=", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
int eq = arg.IndexOf('=');
|
int eq = arg.IndexOf('=');
|
||||||
if (ulong.TryParse(arg.AsSpan(eq + 1), out var kmax))
|
if (UInt128.TryParse(arg.AsSpan(eq + 1), NumberStyles.Integer, provider: null, out var kmax))
|
||||||
{
|
{
|
||||||
residueKMax = kmax;
|
residueKMax = kmax;
|
||||||
}
|
}
|
||||||
@@ -449,7 +455,7 @@ internal static class Program
|
|||||||
useGpuOrder: orderOnGpu,
|
useGpuOrder: orderOnGpu,
|
||||||
useResidue: useResidue,
|
useResidue: useResidue,
|
||||||
maxK: residueKMax,
|
maxK: residueKMax,
|
||||||
residueDivisorSets: divisorCyclesSearchLimit);
|
residueDivisorSets: divisorCyclesSearchLimit128);
|
||||||
if (!useLucas)
|
if (!useLucas)
|
||||||
{
|
{
|
||||||
tester.WarmUpOrders(currentP, _orderWarmupLimitOverride ?? 5_000_000UL);
|
tester.WarmUpOrders(currentP, _orderWarmupLimitOverride ?? 5_000_000UL);
|
||||||
@@ -741,7 +747,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 (UInt128 supported; residue path honors full range)");
|
||||||
|
|
||||||
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");
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class MersenneNumberResidueCpuTesterTests
|
|||||||
(UInt128)exponent << 1,
|
(UInt128)exponent << 1,
|
||||||
LastDigitIsSeven(exponent),
|
LastDigitIsSeven(exponent),
|
||||||
(UInt128)maxK,
|
(UInt128)maxK,
|
||||||
1UL,
|
UInt128.One,
|
||||||
(UInt128)maxK,
|
(UInt128)maxK,
|
||||||
ref isPrime,
|
ref isPrime,
|
||||||
ref exhausted);
|
ref exhausted);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class MersenneNumberResidueGpuTesterTests
|
|||||||
(UInt128)exponent << 1,
|
(UInt128)exponent << 1,
|
||||||
LastDigitIsSeven(exponent),
|
LastDigitIsSeven(exponent),
|
||||||
(UInt128)maxK,
|
(UInt128)maxK,
|
||||||
1UL,
|
UInt128.One,
|
||||||
(UInt128)maxK,
|
(UInt128)maxK,
|
||||||
ref isPrime,
|
ref isPrime,
|
||||||
ref exhausted);
|
ref exhausted);
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ public class MersenneNumberResidueCpuTester
|
|||||||
UInt128 twoP,
|
UInt128 twoP,
|
||||||
bool lastIsSeven,
|
bool lastIsSeven,
|
||||||
UInt128 perSetLimit,
|
UInt128 perSetLimit,
|
||||||
ulong setCount,
|
UInt128 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 == UInt128.Zero || perSetLimit == UInt128.Zero || overallLimit == UInt128.Zero)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -52,9 +52,9 @@ public class MersenneNumberResidueCpuTester
|
|||||||
|
|
||||||
ModResidueTracker tracker = _mersenneResidueTracker!;
|
ModResidueTracker tracker = _mersenneResidueTracker!;
|
||||||
UInt128 limitInclusive = overallLimit + UInt128.One;
|
UInt128 limitInclusive = overallLimit + UInt128.One;
|
||||||
for (ulong setIndex = 0; setIndex < setCount && Volatile.Read(ref isPrime); setIndex++)
|
for (UInt128 setIndex = UInt128.Zero; setIndex < setCount && Volatile.Read(ref isPrime); setIndex++)
|
||||||
{
|
{
|
||||||
UInt128 setOffset = perSetLimit * (UInt128)setIndex;
|
UInt128 setOffset = perSetLimit * setIndex;
|
||||||
UInt128 k = setOffset + UInt128.One;
|
UInt128 k = setOffset + UInt128.One;
|
||||||
if (k >= limitInclusive)
|
if (k >= limitInclusive)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
UInt128 twoP,
|
UInt128 twoP,
|
||||||
bool lastIsSeven,
|
bool lastIsSeven,
|
||||||
UInt128 perSetLimit,
|
UInt128 perSetLimit,
|
||||||
ulong setCount,
|
UInt128 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 == UInt128.Zero || perSetLimit == UInt128.Zero || overallLimit == UInt128.Zero)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -48,9 +48,9 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
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 (UInt128 setIndex = UInt128.Zero; setIndex < setCount && Volatile.Read(ref isPrime); setIndex++)
|
||||||
{
|
{
|
||||||
UInt128 setOffset = perSetLimit * (UInt128)setIndex;
|
UInt128 setOffset = perSetLimit * setIndex;
|
||||||
UInt128 setStart = setOffset + UInt128.One;
|
UInt128 setStart = setOffset + UInt128.One;
|
||||||
if (setStart >= limitInclusive)
|
if (setStart >= limitInclusive)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ public sealed class MersenneNumberTester(
|
|||||||
bool useGpuScan = true,
|
bool useGpuScan = true,
|
||||||
bool useGpuOrder = true,
|
bool useGpuOrder = true,
|
||||||
bool useResidue = true,
|
bool useResidue = true,
|
||||||
ulong maxK = 5_000_000UL,
|
UInt128? maxK = null,
|
||||||
ulong residueDivisorSets = PerfectNumberConstants.ExtraDivisorCycleSearchLimit)
|
UInt128? residueDivisorSets = null)
|
||||||
{
|
{
|
||||||
private readonly bool _useResidue = useResidue;
|
private readonly bool _useResidue = useResidue;
|
||||||
private readonly bool _useIncremental = useIncremental && !useResidue;
|
private readonly bool _useIncremental = useIncremental && !useResidue;
|
||||||
private readonly ulong _maxK = maxK;
|
private readonly UInt128 _maxK = maxK ?? (UInt128)5_000_000UL;
|
||||||
private readonly ulong _residueDivisorSetCount = residueDivisorSets;
|
private readonly UInt128 _residueDivisorSetCount = residueDivisorSets ?? (UInt128)PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
|
||||||
private readonly GpuKernelType _kernelType = kernelType;
|
private readonly GpuKernelType _kernelType = kernelType;
|
||||||
private readonly bool _useModuloWorkaround = useModuloWorkaround;
|
private readonly bool _useModuloWorkaround = useModuloWorkaround;
|
||||||
private readonly bool _useGpuLucas = useGpuLucas;
|
private readonly bool _useGpuLucas = useGpuLucas;
|
||||||
@@ -246,17 +246,17 @@ public sealed class MersenneNumberTester(
|
|||||||
// In residue mode the residue scan is the final primality check.
|
// In residue mode the residue scan is the final primality check.
|
||||||
if (_useResidue)
|
if (_useResidue)
|
||||||
{
|
{
|
||||||
if ((UInt128)_maxK < maxK)
|
if (_maxK < maxK)
|
||||||
{
|
{
|
||||||
maxK = _maxK;
|
maxK = _maxK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_maxK == 0UL || _residueDivisorSetCount == 0UL)
|
if (_maxK == UInt128.Zero || _residueDivisorSetCount == UInt128.Zero)
|
||||||
{
|
{
|
||||||
return prePrime;
|
return prePrime;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 totalLimit = (UInt128)_maxK;
|
UInt128 totalLimit = _maxK;
|
||||||
if (totalLimit > maxK)
|
if (totalLimit > maxK)
|
||||||
{
|
{
|
||||||
totalLimit = maxK;
|
totalLimit = maxK;
|
||||||
@@ -267,23 +267,23 @@ public sealed class MersenneNumberTester(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong requestedSets = _residueDivisorSetCount;
|
UInt128 requestedSets = _residueDivisorSetCount;
|
||||||
if (requestedSets == 0UL)
|
if (requestedSets == UInt128.Zero)
|
||||||
{
|
{
|
||||||
requestedSets = 1UL;
|
requestedSets = UInt128.One;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 perSetLimit = DivideRoundUp(totalLimit, (UInt128)requestedSets);
|
UInt128 perSetLimit = DivideRoundUp(totalLimit, requestedSets);
|
||||||
if (perSetLimit == UInt128.Zero)
|
if (perSetLimit == UInt128.Zero)
|
||||||
{
|
{
|
||||||
perSetLimit = UInt128.One;
|
perSetLimit = UInt128.One;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 setsNeeded = DivideRoundUp(totalLimit, perSetLimit);
|
UInt128 setsNeeded = DivideRoundUp(totalLimit, perSetLimit);
|
||||||
ulong effectiveSets = requestedSets;
|
UInt128 effectiveSets = requestedSets;
|
||||||
if (setsNeeded < (UInt128)effectiveSets)
|
if (setsNeeded < effectiveSets)
|
||||||
{
|
{
|
||||||
effectiveSets = (ulong)setsNeeded;
|
effectiveSets = setsNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scanCompleted = false;
|
bool scanCompleted = false;
|
||||||
|
|||||||
Reference in new issue
Block a user