Merge pull request #33 from mlemanczyk/codex/verify-divisor-set-in-mersenne=residue

Align residue GPU divisor limit with divisor mode
This commit is contained in:
Marek Lemańczyk authored and GitHub committed 2025-09-20 03:51:06 +02:00
commit 52a27dfe61
3 files changed
+63

No files matched your search

@@ -38,6 +38,28 @@ public class ProgramTests
Program.TransformPAdd(7UL, ref remainder).Should().Be(11UL); Program.TransformPAdd(7UL, ref remainder).Should().Be(11UL);
} }
[Theory]
[InlineData(false, false, false, 5UL, 1024UL, 5UL)]
[InlineData(true, false, false, 5UL, 1024UL, 5UL)]
[InlineData(true, true, true, 7UL, 1024UL, 7UL)]
[InlineData(true, false, true, 5UL, 1024UL, 1024UL)]
[InlineData(true, true, false, 5UL, 1024UL, 5UL)]
public void ResolveResidueMaxK_applies_expected_rules(
bool useResidue,
bool residueMaxExplicit,
bool divisorLimitExplicit,
ulong residueMaxK,
ulong divisorLimit,
ulong expected)
{
Program.ResolveResidueMaxK(
useResidue,
residueMaxExplicit,
divisorLimitExplicit,
residueMaxK,
divisorLimit).Should().Be((UInt128)expected);
}
[Fact] [Fact]
public void TransformPBit_appends_one_bit_and_skips_to_candidate() public void TransformPBit_appends_one_bit_and_skips_to_candidate()
{ {
+27
View File
@@ -75,12 +75,14 @@ internal static class Program
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;
UInt128 residueKMax = 5_000_000UL; UInt128 residueKMax = 5_000_000UL;
bool residueKMaxExplicit = false;
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; UInt128 divisorCyclesSearchLimit128 = PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
ulong divisorCyclesSearchLimit = PerfectNumberConstants.ExtraDivisorCycleSearchLimit; ulong divisorCyclesSearchLimit = PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
bool divisorCyclesLimitExplicit = false;
// NTT backend selection (GPU): reference vs staged // NTT backend selection (GPU): reference vs staged
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
@@ -149,6 +151,7 @@ internal static class Program
{ {
divisorCyclesSearchLimit128 = limit; divisorCyclesSearchLimit128 = limit;
divisorCyclesSearchLimit = limit > (UInt128)ulong.MaxValue ? ulong.MaxValue : (ulong)limit; divisorCyclesSearchLimit = limit > (UInt128)ulong.MaxValue ? ulong.MaxValue : (ulong)limit;
divisorCyclesLimitExplicit = true;
} }
} }
else if (arg.StartsWith("--residue-max-k=", StringComparison.OrdinalIgnoreCase)) else if (arg.StartsWith("--residue-max-k=", StringComparison.OrdinalIgnoreCase))
@@ -157,6 +160,7 @@ internal static class Program
if (UInt128.TryParse(arg.AsSpan(eq + 1), NumberStyles.Integer, provider: null, out var kmax)) if (UInt128.TryParse(arg.AsSpan(eq + 1), NumberStyles.Integer, provider: null, out var kmax))
{ {
residueKMax = kmax; residueKMax = kmax;
residueKMaxExplicit = true;
} }
} }
// Replaces --lucas=cpu|gpu; controls device for Lucas and for // Replaces --lucas=cpu|gpu; controls device for Lucas and for
@@ -368,6 +372,8 @@ internal static class Program
} }
} }
residueKMax = ResolveResidueMaxK(useResidue, residueKMaxExplicit, divisorCyclesLimitExplicit, residueKMax, divisorCyclesSearchLimit128);
if (showHelp) if (showHelp)
{ {
PrintHelp(); PrintHelp();
@@ -1104,6 +1110,27 @@ internal static class Program
return mersennePrime; return mersennePrime;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static UInt128 ResolveResidueMaxK(
bool useResidue,
bool residueMaxExplicit,
bool divisorLimitExplicit,
UInt128 residueMaxK,
UInt128 divisorLimit)
{
if (!useResidue)
{
return residueMaxK;
}
if (residueMaxExplicit || !divisorLimitExplicit)
{
return residueMaxK;
}
return divisorLimit;
}
// Use ModResidueTracker with a small set of primes to pre-filter composite p. // Use ModResidueTracker with a small set of primes to pre-filter composite p.
private static bool IsCompositeByResidues(ulong p) private static bool IsCompositeByResidues(ulong p)
{ {
@@ -268,6 +268,20 @@ public sealed class MersenneNumberTester(
} }
UInt128 requestedSets = _residueDivisorSetCount; UInt128 requestedSets = _residueDivisorSetCount;
if (_useGpuScan)
{
UInt128 maxUsefulSets = DivideRoundUp(totalLimit, (UInt128)GpuConstants.ScanBatchSize);
if (maxUsefulSets == UInt128.Zero)
{
maxUsefulSets = UInt128.One;
}
if (requestedSets == UInt128.Zero || requestedSets > maxUsefulSets)
{
requestedSets = maxUsefulSets;
}
}
if (requestedSets == UInt128.Zero) if (requestedSets == UInt128.Zero)
{ {
requestedSets = UInt128.One; requestedSets = UInt128.One;