Add wide heuristic benchmark
This commit is contained in:
1 parent
07dad89fdf
commit
8068a62f55
1 file changed
+60
@@ -28,15 +28,18 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
|||||||
private readonly MontgomeryDivisorData[] _smallDivisors = new MontgomeryDivisorData[SampleCount];
|
private readonly MontgomeryDivisorData[] _smallDivisors = new MontgomeryDivisorData[SampleCount];
|
||||||
private readonly MontgomeryDivisorData[] _largeDivisors = new MontgomeryDivisorData[SampleCount];
|
private readonly MontgomeryDivisorData[] _largeDivisors = new MontgomeryDivisorData[SampleCount];
|
||||||
private readonly MontgomeryDivisorData[] _veryLargeDivisors = new MontgomeryDivisorData[SampleCount];
|
private readonly MontgomeryDivisorData[] _veryLargeDivisors = new MontgomeryDivisorData[SampleCount];
|
||||||
|
private readonly UInt128[] _wideModuli = new UInt128[SampleCount];
|
||||||
private readonly ulong[] _smallExponents = new ulong[SampleCount];
|
private readonly ulong[] _smallExponents = new ulong[SampleCount];
|
||||||
private readonly ulong[] _largeExponents = new ulong[SampleCount];
|
private readonly ulong[] _largeExponents = new ulong[SampleCount];
|
||||||
private readonly ulong[] _veryLargeExponents = new ulong[SampleCount];
|
private readonly ulong[] _veryLargeExponents = new ulong[SampleCount];
|
||||||
private readonly ulong[] _smallCycles = new ulong[SampleCount];
|
private readonly ulong[] _smallCycles = new ulong[SampleCount];
|
||||||
private readonly ulong[] _largeCycles = new ulong[SampleCount];
|
private readonly ulong[] _largeCycles = new ulong[SampleCount];
|
||||||
private readonly ulong[] _veryLargeCycles = new ulong[SampleCount];
|
private readonly ulong[] _veryLargeCycles = new ulong[SampleCount];
|
||||||
|
private readonly UInt128[] _wideCycles = new UInt128[SampleCount];
|
||||||
|
|
||||||
private readonly Random _random = new(113);
|
private readonly Random _random = new(113);
|
||||||
private ulong? _previousPrimeOrder;
|
private ulong? _previousPrimeOrder;
|
||||||
|
private UInt128? _previousWidePrimeOrder;
|
||||||
|
|
||||||
public enum InputScale
|
public enum InputScale
|
||||||
{
|
{
|
||||||
@@ -73,6 +76,10 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
|||||||
Console.WriteLine($"Calculating cycle length {veryLargeModulus}");
|
Console.WriteLine($"Calculating cycle length {veryLargeModulus}");
|
||||||
#endif
|
#endif
|
||||||
_veryLargeCycles[i] = CalculateCycleLengthWithHeuristics(veryLargeModulus);
|
_veryLargeCycles[i] = CalculateCycleLengthWithHeuristics(veryLargeModulus);
|
||||||
|
|
||||||
|
UInt128 wideModulus = NextWideOddModulus();
|
||||||
|
_wideModuli[i] = wideModulus;
|
||||||
|
_wideCycles[i] = CalculateCycleLengthWithHeuristics(wideModulus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +154,21 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
|||||||
return checksum;
|
return checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public UInt128 HeuristicWideCycleComputation()
|
||||||
|
{
|
||||||
|
UInt128 checksum = UInt128.Zero;
|
||||||
|
|
||||||
|
for (int i = 0; i < SampleCount; i++)
|
||||||
|
{
|
||||||
|
UInt128 cycle = CalculateCycleLengthWithHeuristics(_wideModuli[i]);
|
||||||
|
_wideCycles[i] = cycle;
|
||||||
|
checksum ^= cycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
private void GetData(out ulong[] exponents, out MontgomeryDivisorData[] divisors, out ulong[] cycles)
|
private void GetData(out ulong[] exponents, out MontgomeryDivisorData[] divisors, out ulong[] cycles)
|
||||||
{
|
{
|
||||||
switch (Scale)
|
switch (Scale)
|
||||||
@@ -204,6 +226,17 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UInt128 NextWideOddModulus()
|
||||||
|
{
|
||||||
|
Span<byte> buffer = stackalloc byte[16];
|
||||||
|
_random.NextBytes(buffer);
|
||||||
|
ulong low = BinaryPrimitives.ReadUInt64LittleEndian(buffer);
|
||||||
|
Span<byte> highSlice = buffer.Slice(8, 8);
|
||||||
|
ulong high = BinaryPrimitives.ReadUInt64LittleEndian(highSlice) | (1UL << 63);
|
||||||
|
UInt128 value = ((UInt128)high << 64) | low;
|
||||||
|
return value | UInt128.One;
|
||||||
|
}
|
||||||
|
|
||||||
private static MontgomeryDivisorData CreateMontgomeryDivisorData(ulong modulus)
|
private static MontgomeryDivisorData CreateMontgomeryDivisorData(ulong modulus)
|
||||||
{
|
{
|
||||||
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
||||||
@@ -261,6 +294,33 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
|||||||
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLength(modulus);
|
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLength(modulus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UInt128 CalculateCycleLengthWithHeuristics(UInt128 modulus)
|
||||||
|
{
|
||||||
|
if (modulus <= UInt128.One || (modulus & UInt128.One) == UInt128.Zero)
|
||||||
|
{
|
||||||
|
return MersenneDivisorCycles.GetCycle(modulus);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Console.WriteLine("Trying heuristic. Wide prime order calculation");
|
||||||
|
#endif
|
||||||
|
PrimeOrderCalculator.PrimeOrderResultWide orderResult = PrimeOrderCalculator.Calculate(
|
||||||
|
modulus,
|
||||||
|
_previousWidePrimeOrder,
|
||||||
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||||
|
|
||||||
|
if (orderResult.Order != UInt128.Zero)
|
||||||
|
{
|
||||||
|
_previousWidePrimeOrder = orderResult.Order;
|
||||||
|
return orderResult.Order;
|
||||||
|
}
|
||||||
|
|
||||||
|
_previousWidePrimeOrder = null;
|
||||||
|
|
||||||
|
Console.WriteLine($"Wide heuristic failed for {modulus}, falling back to full cycle calculation");
|
||||||
|
return MersenneDivisorCycles.GetCycle(modulus);
|
||||||
|
}
|
||||||
|
|
||||||
private static ulong ComputeMontgomeryResidue(ulong value, ulong modulus) => (ulong)((UInt128)value * (UInt128.One << 64) % modulus);
|
private static ulong ComputeMontgomeryResidue(ulong value, ulong modulus) => (ulong)((UInt128)value * (UInt128.One << 64) % modulus);
|
||||||
|
|
||||||
private static ulong ComputeMontgomeryNPrime(ulong modulus)
|
private static ulong ComputeMontgomeryNPrime(ulong modulus)
|
||||||
|
|||||||
Reference in new issue
Block a user