Restored outputting of candidates which failed some tests

This commit is contained in:
Marek Lemańczyk committed 2025-09-20 08:30:20 +02:00
1 parent afcc8d87f9
commit 5420523a0a
1 file changed
+127 -143
+127 -143
View File
@@ -40,8 +40,8 @@ internal static class Program
private static string? _resultsPrefix; private static string? _resultsPrefix;
private static readonly Optimized PrimeIterator = new(); private static readonly Optimized PrimeIterator = new();
[ThreadStatic] [ThreadStatic]
private static bool _lastCompositeP; private static bool _lastCompositeP;
// RLE/bit-pattern filtering options // RLE/bit-pattern filtering options
private static string? _rleBlacklistPath; private static string? _rleBlacklistPath;
@@ -74,15 +74,15 @@ 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;
UInt128 residueKMax = 5_000_000UL; UInt128 residueKMax = 5_000_000UL;
bool residueKMaxExplicit = false; 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; 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++)
@@ -144,25 +144,25 @@ internal static class Program
int eq = arg.IndexOf('='); int eq = arg.IndexOf('=');
divisor = UInt128.Parse(arg.AsSpan(eq + 1)); divisor = UInt128.Parse(arg.AsSpan(eq + 1));
} }
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('=');
if (UInt128.TryParse(arg.AsSpan(eq + 1), NumberStyles.Integer, provider: null, out var limit)) if (UInt128.TryParse(arg.AsSpan(eq + 1), NumberStyles.Integer, provider: null, out var limit))
{ {
divisorCyclesSearchLimit128 = limit; divisorCyclesSearchLimit128 = limit;
divisorCyclesSearchLimit = limit > (UInt128)ulong.MaxValue ? ulong.MaxValue : (ulong)limit; divisorCyclesSearchLimit = limit > (UInt128)ulong.MaxValue ? ulong.MaxValue : (ulong)limit;
divisorCyclesLimitExplicit = true; divisorCyclesLimitExplicit = true;
} }
} }
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 (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; residueKMaxExplicit = true;
} }
} }
// Replaces --lucas=cpu|gpu; controls device for Lucas and for // Replaces --lucas=cpu|gpu; controls device for Lucas and for
// incremental/pow2mod scanning // incremental/pow2mod scanning
else if (arg.StartsWith("--mersenne-device=", StringComparison.OrdinalIgnoreCase)) else if (arg.StartsWith("--mersenne-device=", StringComparison.OrdinalIgnoreCase))
@@ -372,13 +372,13 @@ internal static class Program
} }
} }
residueKMax = ResolveResidueMaxK(useResidue, residueKMaxExplicit, divisorCyclesLimitExplicit, residueKMax, divisorCyclesSearchLimit128); residueKMax = ResolveResidueMaxK(useResidue, residueKMaxExplicit, divisorCyclesLimitExplicit, residueKMax, divisorCyclesSearchLimit128);
if (showHelp) if (showHelp)
{ {
PrintHelp(); PrintHelp();
return; return;
} }
// Apply GPU prime sieve runtime configuration // Apply GPU prime sieve runtime configuration
GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads); GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads);
@@ -460,8 +460,8 @@ internal static class Program
useGpuScan: mersenneOnGpu, useGpuScan: mersenneOnGpu,
useGpuOrder: orderOnGpu, useGpuOrder: orderOnGpu,
useResidue: useResidue, useResidue: useResidue,
maxK: residueKMax, maxK: residueKMax,
residueDivisorSets: divisorCyclesSearchLimit128); residueDivisorSets: divisorCyclesSearchLimit128);
if (!useLucas) if (!useLucas)
{ {
tester.WarmUpOrders(currentP, _orderWarmupLimitOverride ?? 5_000_000UL); tester.WarmUpOrders(currentP, _orderWarmupLimitOverride ?? 5_000_000UL);
@@ -773,7 +773,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 (UInt128 supported; residue path honors full range)"); 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");
@@ -842,70 +842,54 @@ internal static class Program
} }
} }
bool lastWasComposite = _lastCompositeP; bool lastWasComposite = _lastCompositeP;
bool primeFlag = false, printToConsole = false; bool primeFlag = false, printToConsole = false;
StringBuilder? localBuilder = passedAllTests ? StringBuilderPool.Rent() : null; StringBuilder localBuilder = StringBuilderPool.Rent();
if (localBuilder is not null) _ = localBuilder
{ .Append(currentP).Append(',')
_ = localBuilder .Append(searchedMersenne).Append(',')
.Append(currentP).Append(',') .Append(detailedCheck).Append(',')
.Append(searchedMersenne).Append(',') .Append(passedAllTests).Append('\n');
.Append(detailedCheck).Append(',')
.Append(passedAllTests).Append('\n');
}
lock (Sync) lock (Sync)
{ {
if (_consoleCounter >= ConsoleInterval) if (_consoleCounter >= ConsoleInterval)
{ {
printToConsole = true; printToConsole = true;
primeFlag = passedAllTests && !lastWasComposite && _primeFoundAfterInit; primeFlag = passedAllTests && !lastWasComposite && _primeFoundAfterInit;
_consoleCounter = 0; _consoleCounter = 0;
} }
else else
{ {
_consoleCounter++; _consoleCounter++;
} }
if (localBuilder is not null) _ = _outputBuilder!.Append(localBuilder);
{
_ = _outputBuilder!.Append(localBuilder);
_writeIndex++; _writeIndex++;
if (_writeIndex >= _writeBatchSize) if (_writeIndex >= _writeBatchSize)
{ {
FlushBuffer(); FlushBuffer();
} }
} }
}
if (printToConsole) if (printToConsole)
{ {
if (localBuilder is not null) if (primeFlag)
{ {
if (primeFlag) _ = localBuilder
{ .Remove(localBuilder.Length - 1, 1)
_ = localBuilder .Append(PrimeFoundSuffix)
.Remove(localBuilder.Length - 1, 1) .Append('\n');
.Append(PrimeFoundSuffix) }
.Append('\n');
}
Console.WriteLine(localBuilder.Remove(localBuilder.Length - 1, 1).ToString()); Console.WriteLine(localBuilder.Remove(localBuilder.Length - 1, 1).ToString());
} }
else
{
Console.WriteLine($"{currentP},{searchedMersenne},{detailedCheck},{passedAllTests}");
}
}
if (localBuilder is not null) localBuilder.Clear();
{ StringBuilderPool.Return(localBuilder);
localBuilder.Clear(); }
StringBuilderPool.Return(localBuilder);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void FlushBuffer() private static void FlushBuffer()
@@ -956,11 +940,11 @@ internal static class Program
} }
ulong next = (value << 1) | 1UL; ulong next = (value << 1) | 1UL;
remainder = (remainder << 1) + 1UL; remainder = (remainder << 1) + 1UL;
while (remainder >= 6UL) while (remainder >= 6UL)
{ {
remainder -= 6UL; remainder -= 6UL;
} }
value = remainder switch value = remainder switch
{ {
@@ -978,11 +962,11 @@ internal static class Program
return original; return original;
} }
remainder += value; remainder += value;
while (remainder >= 6UL) while (remainder >= 6UL)
{ {
remainder -= 6UL; remainder -= 6UL;
} }
return next + value; return next + value;
} }
@@ -999,11 +983,11 @@ internal static class Program
return next; return next;
} }
remainder += diff; remainder += diff;
while (remainder >= 6UL) while (remainder >= 6UL)
{ {
remainder -= 6UL; remainder -= 6UL;
} }
return next + diff; return next + diff;
} }
@@ -1031,11 +1015,11 @@ internal static class Program
} }
candidate += diff; candidate += diff;
addRemainder += diff; addRemainder += diff;
while (addRemainder >= 6UL) while (addRemainder >= 6UL)
{ {
addRemainder -= 6UL; addRemainder -= 6UL;
} }
} }
if (advancePrime) if (advancePrime)
@@ -1149,37 +1133,37 @@ internal static class Program
return _divisorTester!.IsPrime(p, _divisor, divisorCyclesSearchLimit, out detailedCheck); return _divisorTester!.IsPrime(p, _divisor, divisorCyclesSearchLimit, out detailedCheck);
} }
bool mersennePrime = MersenneTesters.Value!.IsMersennePrime(p, out bool residueExhausted); bool mersennePrime = MersenneTesters.Value!.IsMersennePrime(p, out bool residueExhausted);
detailedCheck = residueExhausted; detailedCheck = residueExhausted;
return mersennePrime; return mersennePrime;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static UInt128 ResolveResidueMaxK( internal static UInt128 ResolveResidueMaxK(
bool useResidue, bool useResidue,
bool residueMaxExplicit, bool residueMaxExplicit,
bool divisorLimitExplicit, bool divisorLimitExplicit,
UInt128 residueMaxK, UInt128 residueMaxK,
UInt128 divisorLimit) UInt128 divisorLimit)
{ {
if (!useResidue) if (!useResidue)
{ {
return residueMaxK; return residueMaxK;
} }
if (residueMaxExplicit || !divisorLimitExplicit) if (residueMaxExplicit || !divisorLimitExplicit)
{ {
return residueMaxK; return residueMaxK;
} }
return divisorLimit; 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)
{ {
var tracker = PResidue.Value!; var tracker = PResidue.Value!;
tracker.BeginMerge(p); tracker.BeginMerge(p);
// Use the small prime list from PerfectNumbers.Core to the extent of sqrt(p) // Use the small prime list from PerfectNumbers.Core to the extent of sqrt(p)
var primes = PrimesGenerator.SmallPrimes; var primes = PrimesGenerator.SmallPrimes;
var primesPow2 = PrimesGenerator.SmallPrimesPow2; var primesPow2 = PrimesGenerator.SmallPrimesPow2;