Refine GPU residue prime tables

This commit is contained in:
Marek Lemańczyk committed 2025-09-17 17:35:26 +02:00
1 parent 88d0c9c271
commit 34cc0b0fdd
5 files changed
+209 -99

No files matched your search

+98 -65
View File
@@ -1,80 +1,113 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core;
public static class PrimesGenerator
{
private static uint[]? _primes;
private static ulong[]? _primesPow2;
public static readonly uint[] SmallPrimes;
public static readonly ulong[] SmallPrimesPow2;
public static readonly uint[] SmallPrimesLastOne;
public static readonly ulong[] SmallPrimesPow2LastOne;
public static readonly uint[] SmallPrimesLastSeven;
public static readonly ulong[] SmallPrimesPow2LastSeven;
public static readonly uint[] SmallPrimes = BuildSmallPrimesInternal();
public static readonly ulong[] SmallPrimesPow2 = BuildSmallPrimesPow2Internal();
static PrimesGenerator()
{
BuildSmallPrimes(
out SmallPrimes,
out SmallPrimesPow2,
out SmallPrimesLastOne,
out SmallPrimesPow2LastOne,
out SmallPrimesLastSeven,
out SmallPrimesPow2LastSeven);
}
private static void BuildSmallPrimes(
out uint[] all,
out ulong[] allPow2,
out uint[] lastOne,
out ulong[] lastOnePow2,
out uint[] lastSeven,
out ulong[] lastSevenPow2)
{
uint target = PerfectNumberConstants.PrimesLimit;
int targetInt = checked((int)target);
all = new uint[targetInt];
allPow2 = new ulong[targetInt];
lastOne = new uint[targetInt];
lastOnePow2 = new ulong[targetInt];
lastSeven = new uint[targetInt];
lastSevenPow2 = new ulong[targetInt];
private static uint[] BuildSmallPrimesInternal()
{
if (_primes == null)
{
BuildSmallPrimes();
}
List<uint> primes = new(targetInt * 4 / 3 + 16);
uint candidate = 2U;
int allCount = 0;
int lastOneCount = 0;
int lastSevenCount = 0;
return _primes!;
}
while (allCount < targetInt || lastOneCount < targetInt || lastSevenCount < targetInt)
{
bool isPrime = true;
int primesCount = primes.Count;
for (int i = 0; i < primesCount; i++)
{
uint p = primes[i];
if (p * p > candidate)
{
break;
}
private static ulong[] BuildSmallPrimesPow2Internal()
{
if (_primesPow2 == null)
{
BuildSmallPrimes();
}
if (candidate % p == 0U)
{
isPrime = false;
break;
}
}
return _primesPow2!;
}
if (isPrime)
{
primes.Add(candidate);
if (allCount < targetInt)
{
all[allCount] = candidate;
allPow2[allCount] = checked((ulong)candidate * candidate);
allCount++;
}
private static void BuildSmallPrimes()
{
uint limit = PerfectNumberConstants.PrimesLimit;
var primes = new uint[limit];
primes[0] = 2;
var primesPow2 = new ulong[limit];
primesPow2[0] = 4;
if (candidate != 2U)
{
if (lastOneCount < targetInt && IsAllowedForLastOne(candidate))
{
lastOne[lastOneCount] = candidate;
lastOnePow2[lastOneCount] = checked((ulong)candidate * candidate);
lastOneCount++;
}
int j;
uint i = 3, p, sqrt;
bool isPrime;
int primeIndex = 1;
if (lastSevenCount < targetInt && IsAllowedForLastSeven(candidate))
{
lastSeven[lastSevenCount] = candidate;
lastSevenPow2[lastSevenCount] = checked((ulong)candidate * candidate);
lastSevenCount++;
}
}
}
for (; i <= limit; i += 2)
{
isPrime = true;
sqrt = (uint)Math.Sqrt(i);
for (j = 0; j < primeIndex; j++)
{
p = primes[j];
if (p > sqrt)
{
break;
}
candidate = candidate == 2U ? 3U : candidate + 2U;
}
}
if (i % p == 0UL)
{
isPrime = false;
break;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsAllowedForLastOne(uint prime)
{
uint mod10 = prime % 10U;
return mod10 == 1U || mod10 == 3U || mod10 == 9U || prime == 7U || prime == 11U;
}
if (isPrime)
{
primes[primeIndex] = i;
primesPow2[primeIndex] = checked((ulong)i * i);
primeIndex++;
}
}
Array.Resize(ref primes, primeIndex);
Array.Resize(ref primesPow2, primeIndex);
_primes = primes;
_primesPow2 = primesPow2;
return;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsAllowedForLastSeven(uint prime)
{
uint mod10 = prime % 10U;
return mod10 == 3U || mod10 == 7U || mod10 == 9U || prime == 11U;
}
}