Fix divisor cycle generation range partitioning

This commit is contained in:
Marek Lemańczyk committed 2025-09-24 17:22:20 +02:00
1 parent 283913375b
commit b69a1101c4
2 files changed
+123 -50

No files matched your search

+70 -50
View File
@@ -150,65 +150,85 @@ public class MersenneDivisorCycles
private const int BufferSize10M = 10 * 1024 * 1024;
public static void Generate(string path, ulong maxDivisor, int threads = 16)
{
// Binary-only generation of (divisor, cycle) pairs. CSV scaffolding removed.
ulong start, d = start = 2;
ulong blockSize = maxDivisor / (ulong)threads + 1;
Task[] tasks = new Task[threads];
using Stream outputStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, BufferSize10M, useAsync: false);
// Start fresh to avoid mixing formats
outputStream.SetLength(0L);
outputStream.Position = 0L;
using var writer = new BinaryWriter(outputStream, Encoding.UTF8, leaveOpen: false);
for (var taskIndex = 0; taskIndex < threads; taskIndex++)
{
Task t = Task.Factory.StartNew((taskIndex) =>
{
ulong cycle, d = start + (ulong)(int)taskIndex! * blockSize;
(ulong d, ulong cycle)[] localCycles = ArrayPool<(ulong, ulong)>.Shared.Rent((int)(maxDivisor - d + 1UL));
int localCycleIndex = 0;
for (; d <= maxDivisor; d++)
{
if ((d & 1UL) == 0UL)
{
// skip even divisors
continue;
}
public static void Generate(string path, ulong maxDivisor, int threads = 16)
{
// Binary-only generation of (divisor, cycle) pairs. CSV scaffolding removed.
ulong start = 2;
ulong blockSize = maxDivisor / (ulong)threads + 1UL;
Task[] tasks = new Task[threads];
using Stream outputStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, BufferSize10M, useAsync: false);
// Start fresh to avoid mixing formats
outputStream.SetLength(0L);
outputStream.Position = 0L;
using var writer = new BinaryWriter(outputStream, Encoding.UTF8, leaveOpen: false);
for (var taskIndex = 0; taskIndex < threads; taskIndex++)
{
ulong threadStart = start + (ulong)taskIndex * blockSize;
if (threadStart > maxDivisor)
{
tasks[taskIndex] = Task.CompletedTask;
continue;
}
cycle = CalculateCycleLength(d);
ulong threadEnd = threadStart + blockSize - 1UL;
if (threadEnd > maxDivisor)
{
threadEnd = maxDivisor;
}
localCycles[localCycleIndex++] = (d, cycle);
}
ulong localStart = threadStart;
ulong localEnd = threadEnd;
tasks[taskIndex] = Task.Run(() =>
{
ulong rangeLength = localEnd - localStart + 1UL;
(ulong divisor, ulong cycle)[] localCycles = ArrayPool<(ulong, ulong)>.Shared.Rent(checked((int)rangeLength));
int localCycleIndex = 0;
if (localCycleIndex > 0)
{
lock (writer)
{
writer.BaseStream.Position = writer.BaseStream.Length;
for (int i = 0; i < localCycleIndex; i++)
{
(d, cycle) = localCycles[i];
if ((d % 3UL) == 0UL || (d % 5UL) == 0UL || (d % 7UL) == 0UL || (d % 11UL) == 0UL)
continue;
try
{
for (ulong divisor = localStart; divisor <= localEnd; divisor++)
{
if ((divisor & 1UL) == 0UL)
{
continue;
}
writer.Write(d);
writer.Write(cycle);
}
if ((divisor % 3UL) == 0UL || (divisor % 5UL) == 0UL || (divisor % 7UL) == 0UL || (divisor % 11UL) == 0UL)
{
continue;
}
writer.Flush();
}
}
ulong cycle = CalculateCycleLength(divisor);
localCycles[localCycleIndex++] = (divisor, cycle);
}
ArrayPool<(ulong, ulong)>.Shared.Return(localCycles, clearArray: false);
if (localCycleIndex == 0)
{
return;
}
}, taskIndex);
lock (writer)
{
writer.BaseStream.Position = writer.BaseStream.Length;
for (int i = 0; i < localCycleIndex; i++)
{
(ulong divisor, ulong cycle) = localCycles[i];
writer.Write(divisor);
writer.Write(cycle);
}
tasks[taskIndex] = t;
}
writer.Flush();
}
}
finally
{
ArrayPool<(ulong, ulong)>.Shared.Return(localCycles, clearArray: false);
}
});
}
Task.WaitAll(tasks);
}
Task.WaitAll(tasks);
}
public static void GenerateGpu(string path, ulong maxDivisor, int batchSize = 1_000_000, long skipCount = 0L, long nextPosition = 0L)
{