Use heuristic sieves for prime trial division
This commit is contained in:
1 parent
15c229665d
commit
1f7680a465
4 files changed
+235
-211
No files matched your search
@@ -15,195 +15,111 @@ public static class HeuristicPrimeSieves
|
||||
private static readonly ushort[] GroupBResiduesEnding7 = [17, 37, 47, 67, 97, 107, 127, 137, 157, 167, 187, 197];
|
||||
private static readonly ushort[] GroupBResiduesEnding9 = [19, 29, 59, 79, 89, 109, 139, 149, 169, 179, 199, 209];
|
||||
|
||||
private static int[]? s_groupADivisors;
|
||||
private static ulong[]? s_groupADivisorSquares;
|
||||
private static readonly int[] GroupADivisorsStorage;
|
||||
private static readonly ulong[] GroupADivisorSquaresStorage;
|
||||
|
||||
private static int[]? s_groupBDivisorsEnding1;
|
||||
private static ulong[]? s_groupBDivisorSquaresEnding1;
|
||||
private static readonly int[] GroupBDivisorsEnding1Storage;
|
||||
private static readonly ulong[] GroupBDivisorSquaresEnding1Storage;
|
||||
|
||||
private static int[]? s_groupBDivisorsEnding3;
|
||||
private static ulong[]? s_groupBDivisorSquaresEnding3;
|
||||
private static readonly int[] GroupBDivisorsEnding3Storage;
|
||||
private static readonly ulong[] GroupBDivisorSquaresEnding3Storage;
|
||||
|
||||
private static int[]? s_groupBDivisorsEnding7;
|
||||
private static ulong[]? s_groupBDivisorSquaresEnding7;
|
||||
private static readonly int[] GroupBDivisorsEnding7Storage;
|
||||
private static readonly ulong[] GroupBDivisorSquaresEnding7Storage;
|
||||
|
||||
private static int[]? s_groupBDivisorsEnding9;
|
||||
private static ulong[]? s_groupBDivisorSquaresEnding9;
|
||||
private static readonly int[] GroupBDivisorsEnding9Storage;
|
||||
private static readonly ulong[] GroupBDivisorSquaresEnding9Storage;
|
||||
|
||||
private static readonly object InitLock = new();
|
||||
|
||||
public static ReadOnlySpan<int> GroupADivisors
|
||||
static HeuristicPrimeSieves()
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupAInitialized();
|
||||
return s_groupADivisors!;
|
||||
}
|
||||
Console.WriteLine("[HeuristicPrimeSieves] Initializing heuristic divisor sieves...");
|
||||
|
||||
(GroupADivisorsStorage, GroupADivisorSquaresStorage) = BuildGroupADivisors();
|
||||
(GroupBDivisorsEnding1Storage, GroupBDivisorSquaresEnding1Storage) = BuildGroupBResidueSieve(GroupBResiduesEnding1);
|
||||
(GroupBDivisorsEnding3Storage, GroupBDivisorSquaresEnding3Storage) = BuildGroupBResidueSieve(GroupBResiduesEnding3);
|
||||
(GroupBDivisorsEnding7Storage, GroupBDivisorSquaresEnding7Storage) = BuildGroupBResidueSieve(GroupBResiduesEnding7);
|
||||
(GroupBDivisorsEnding9Storage, GroupBDivisorSquaresEnding9Storage) = BuildGroupBResidueSieve(GroupBResiduesEnding9);
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupADivisorSquares
|
||||
public static void EnsureInitialized()
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupAInitialized();
|
||||
return s_groupADivisorSquares!;
|
||||
}
|
||||
// Intentionally left blank. Accessing this method forces the static constructor to run.
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding1
|
||||
public static ReadOnlySpan<int> GroupADivisors => GroupADivisorsStorage;
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupADivisorSquares => GroupADivisorSquaresStorage;
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding1 => GroupBDivisorsEnding1Storage;
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding1 => GroupBDivisorSquaresEnding1Storage;
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding3 => GroupBDivisorsEnding3Storage;
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding3 => GroupBDivisorSquaresEnding3Storage;
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding7 => GroupBDivisorsEnding7Storage;
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding7 => GroupBDivisorSquaresEnding7Storage;
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding9 => GroupBDivisorsEnding9Storage;
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding9 => GroupBDivisorSquaresEnding9Storage;
|
||||
|
||||
private static (int[] divisors, ulong[] squares) BuildGroupADivisors()
|
||||
{
|
||||
get
|
||||
var divisors = new int[SieveLength];
|
||||
var squares = new ulong[SieveLength];
|
||||
|
||||
int index = 0;
|
||||
for (; index < GroupAConstants.Length && index < divisors.Length; index++)
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding1, ref s_groupBDivisorSquaresEnding1, GroupBResiduesEnding1);
|
||||
return s_groupBDivisorsEnding1!;
|
||||
int value = GroupAConstants[index];
|
||||
divisors[index] = value;
|
||||
squares[index] = (ulong)value * (ulong)value;
|
||||
}
|
||||
|
||||
int candidate = 23;
|
||||
int incrementIndex = 0;
|
||||
while (index < divisors.Length)
|
||||
{
|
||||
divisors[index] = candidate;
|
||||
squares[index] = (ulong)candidate * (ulong)candidate;
|
||||
|
||||
candidate += GroupAIncrementPattern[incrementIndex];
|
||||
incrementIndex ^= 1;
|
||||
index++;
|
||||
}
|
||||
|
||||
return (divisors, squares);
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding1
|
||||
private static (int[] divisors, ulong[] squares) BuildGroupBResidueSieve(ReadOnlySpan<ushort> residues)
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding1, ref s_groupBDivisorSquaresEnding1, GroupBResiduesEnding1);
|
||||
return s_groupBDivisorSquaresEnding1!;
|
||||
}
|
||||
}
|
||||
var divisors = new int[SieveLength];
|
||||
var squares = new ulong[SieveLength];
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding3
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding3, ref s_groupBDivisorSquaresEnding3, GroupBResiduesEnding3);
|
||||
return s_groupBDivisorsEnding3!;
|
||||
}
|
||||
}
|
||||
int index = 0;
|
||||
ulong baseValue = 0UL;
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding3
|
||||
{
|
||||
get
|
||||
while (index < divisors.Length)
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding3, ref s_groupBDivisorSquaresEnding3, GroupBResiduesEnding3);
|
||||
return s_groupBDivisorSquaresEnding3!;
|
||||
}
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding7
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding7, ref s_groupBDivisorSquaresEnding7, GroupBResiduesEnding7);
|
||||
return s_groupBDivisorsEnding7!;
|
||||
}
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding7
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding7, ref s_groupBDivisorSquaresEnding7, GroupBResiduesEnding7);
|
||||
return s_groupBDivisorSquaresEnding7!;
|
||||
}
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<int> GroupBDivisorsEnding9
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding9, ref s_groupBDivisorSquaresEnding9, GroupBResiduesEnding9);
|
||||
return s_groupBDivisorsEnding9!;
|
||||
}
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<ulong> GroupBDivisorSquaresEnding9
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureGroupBInitialized(ref s_groupBDivisorsEnding9, ref s_groupBDivisorSquaresEnding9, GroupBResiduesEnding9);
|
||||
return s_groupBDivisorSquaresEnding9!;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureGroupAInitialized()
|
||||
{
|
||||
if (s_groupADivisors is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (InitLock)
|
||||
{
|
||||
if (s_groupADivisors is not null)
|
||||
for (int i = 0; i < residues.Length && index < divisors.Length; i++)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ulong candidate = baseValue + residues[i];
|
||||
if (candidate <= 13UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var divisors = new int[SieveLength];
|
||||
var squares = new ulong[SieveLength];
|
||||
|
||||
int index = 0;
|
||||
for (; index < GroupAConstants.Length && index < divisors.Length; index++)
|
||||
{
|
||||
int value = GroupAConstants[index];
|
||||
divisors[index] = value;
|
||||
squares[index] = (ulong)value * (ulong)value;
|
||||
}
|
||||
|
||||
int candidate = 23;
|
||||
int incrementIndex = 0;
|
||||
while (index < divisors.Length)
|
||||
{
|
||||
divisors[index] = candidate;
|
||||
squares[index] = (ulong)candidate * (ulong)candidate;
|
||||
|
||||
candidate += GroupAIncrementPattern[incrementIndex];
|
||||
incrementIndex ^= 1;
|
||||
divisors[index] = (int)candidate;
|
||||
squares[index] = candidate * candidate;
|
||||
index++;
|
||||
}
|
||||
|
||||
s_groupADivisors = divisors;
|
||||
s_groupADivisorSquares = squares;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureGroupBInitialized(ref int[]? divisorsField, ref ulong[]? squaresField, ReadOnlySpan<ushort> residues)
|
||||
{
|
||||
if (divisorsField is not null)
|
||||
{
|
||||
return;
|
||||
baseValue += (ulong)Wheel210;
|
||||
}
|
||||
|
||||
lock (InitLock)
|
||||
{
|
||||
if (divisorsField is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var divisors = new int[SieveLength];
|
||||
var squares = new ulong[SieveLength];
|
||||
|
||||
int index = 0;
|
||||
ulong baseValue = 0UL;
|
||||
|
||||
while (index < divisors.Length)
|
||||
{
|
||||
for (int i = 0; i < residues.Length && index < divisors.Length; i++)
|
||||
{
|
||||
ulong candidate = baseValue + residues[i];
|
||||
if (candidate <= 13UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
divisors[index] = (int)candidate;
|
||||
squares[index] = candidate * candidate;
|
||||
index++;
|
||||
}
|
||||
|
||||
baseValue += (ulong)Wheel210;
|
||||
}
|
||||
|
||||
divisorsField = divisors;
|
||||
squaresField = squares;
|
||||
}
|
||||
return (divisors, squares);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user