Merge pull request #65 from mlemanczyk/codex/optimize-modulo-operations-in-extensions
Restore modulo helpers and inline fast remainder utilities
This commit is contained in:
45 files changed
+1043
-108
No files matched your search
@@ -22,10 +22,10 @@ public class Mod10UInt128Benchmarks
|
|||||||
ulong value = (ulong)Value;
|
ulong value = (ulong)Value;
|
||||||
ulong high = value >> 64;
|
ulong high = value >> 64;
|
||||||
ulong low = value;
|
ulong low = value;
|
||||||
ulong highRem = high.Mod10();
|
ulong highRem = high % 10UL;
|
||||||
ulong lowRem = low.Mod10();
|
ulong lowRem = low % 10UL;
|
||||||
ulong combined = lowRem + highRem * 6UL;
|
ulong combined = lowRem + highRem * 6UL;
|
||||||
return combined.Mod10();
|
return combined % 10UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
@@ -42,11 +42,11 @@ public class Mod10UInt128Benchmarks
|
|||||||
while (high != zero)
|
while (high != zero)
|
||||||
{
|
{
|
||||||
// 2^64 ≡ 6 (mod 10)
|
// 2^64 ≡ 6 (mod 10)
|
||||||
result = (result + (ulong)high * 6UL).Mod10();
|
result = (result + (ulong)high * 6UL) % 10UL;
|
||||||
high >>= 64;
|
high >>= 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.Mod10();
|
return result % 10UL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod10UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(10U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 10U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod10();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -11,6 +11,13 @@ public class Mod10_8_5_3Benchmarks
|
|||||||
public ulong Value { get; set; }
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
[Benchmark(Baseline = true)]
|
[Benchmark(Baseline = true)]
|
||||||
|
public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) ModuloOperator()
|
||||||
|
{
|
||||||
|
ulong value = Value;
|
||||||
|
return (value % 10UL, value % 8UL, value % 3UL, value % 5UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) LegacyModulo()
|
public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) LegacyModulo()
|
||||||
{
|
{
|
||||||
ulong mod10, mod8, mod3, mod5;
|
ulong mod10, mod8, mod3, mod5;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class Mod10_8_5_3StepsBenchmarks
|
|||||||
{
|
{
|
||||||
Value.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
Value.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
||||||
// Step residues for q += 2*p
|
// Step residues for q += 2*p
|
||||||
mod10 = mod10.Mod10();
|
mod10 %= 10UL;
|
||||||
return (mod10, mod8, mod3, mod5);
|
return (mod10, mod8, mod3, mod5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod11UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(11UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 255UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return (ulong)(Value % 11UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod11();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod11UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(11U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 11U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod11();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod11ULongBenchmarks
|
||||||
|
{
|
||||||
|
[Params(11UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 127UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 11UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod11();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod11_7_5_3Benchmarks
|
||||||
|
{
|
||||||
|
[Params(3UL, 8191UL, 131071UL, 2147483647UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public (ulong Mod11, ulong Mod7, ulong Mod5, ulong Mod3) ModuloOperator()
|
||||||
|
{
|
||||||
|
ulong value = Value;
|
||||||
|
return (value % 11UL, value % 7UL, value % 5UL, value % 3UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public (ulong Mod11, ulong Mod7, ulong Mod5, ulong Mod3) ExtensionMethods()
|
||||||
|
{
|
||||||
|
ulong value = Value;
|
||||||
|
return (value.Mod11(), value.Mod7(), value.Mod5(), value.Mod3());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public (ulong Mod11, ulong Mod7, ulong Mod5, ulong Mod3) CombinedMethod()
|
||||||
|
{
|
||||||
|
Value.Mod11_7_5_3(out ulong mod11, out ulong mod7, out ulong mod5, out ulong mod3);
|
||||||
|
return (mod11, mod7, mod5, mod3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod128UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(128UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 511UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return (ulong)(Value % 128UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod128();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod128UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(128U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 128U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod128();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod128ULongBenchmarks
|
||||||
|
{
|
||||||
|
[Params(128UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 255UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 128UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod128();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod3UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(3UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 17UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return (ulong)(Value % 3UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod3();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod3UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(3U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 3U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod3();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod3ULongBenchmarks
|
||||||
|
{
|
||||||
|
[Params(3UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 17UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 3UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod3();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod5UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(5UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 31UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return (ulong)(Value % 5UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod5();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod5UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(5U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 5U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod5();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod5ULongBenchmarks
|
||||||
|
{
|
||||||
|
[Params(5UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 31UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 5UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod5();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 3)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod6ComparisonBenchmarks
|
||||||
|
{
|
||||||
|
private const int Iterations = 10_000_000;
|
||||||
|
private const ulong Divisor = 6UL;
|
||||||
|
private static readonly ulong FastDivMul = (ulong)(((UInt128)1 << 64) / Divisor);
|
||||||
|
|
||||||
|
[Params(3UL, 131071UL, ulong.MaxValue - 1024UL)]
|
||||||
|
public ulong StartValue { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true, OperationsPerInvoke = Iterations)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
ulong checksum = 0UL;
|
||||||
|
ulong value = StartValue;
|
||||||
|
|
||||||
|
for (int i = 0; i < Iterations; i++)
|
||||||
|
{
|
||||||
|
checksum += value % Divisor;
|
||||||
|
value += (ulong)((i & 15) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = Iterations)]
|
||||||
|
public ulong DivisionBased()
|
||||||
|
{
|
||||||
|
ulong checksum = 0UL;
|
||||||
|
ulong value = StartValue;
|
||||||
|
|
||||||
|
for (int i = 0; i < Iterations; i++)
|
||||||
|
{
|
||||||
|
ulong quotient = value / Divisor;
|
||||||
|
checksum += value - quotient * Divisor;
|
||||||
|
value += (ulong)((i & 15) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = Iterations)]
|
||||||
|
public ulong FastDivHigh()
|
||||||
|
{
|
||||||
|
ulong checksum = 0UL;
|
||||||
|
ulong value = StartValue;
|
||||||
|
|
||||||
|
for (int i = 0; i < Iterations; i++)
|
||||||
|
{
|
||||||
|
ulong quotient = value.FastDiv64(Divisor, FastDivMul);
|
||||||
|
checksum += value - quotient * Divisor;
|
||||||
|
value += (ulong)((i & 15) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = Iterations)]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
ulong checksum = 0UL;
|
||||||
|
ulong value = StartValue;
|
||||||
|
|
||||||
|
for (int i = 0; i < Iterations; i++)
|
||||||
|
{
|
||||||
|
checksum += value.Mod6();
|
||||||
|
value += (ulong)((i & 15) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod6UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(6UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 63UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return (ulong)(Value % 6UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod6();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod6UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(6U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 6U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod6();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 3)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod6ULongBenchmarks
|
||||||
|
{
|
||||||
|
private static readonly ulong Divisor = 6UL;
|
||||||
|
private static readonly ulong FastDivMul = (ulong)(((UInt128)1 << 64) / Divisor);
|
||||||
|
|
||||||
|
[Params(3UL, 131071UL, ulong.MaxValue)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % Divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong DivisionBased()
|
||||||
|
{
|
||||||
|
ulong quotient = Value / Divisor;
|
||||||
|
return Value - quotient * Divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong FastDivHigh()
|
||||||
|
{
|
||||||
|
ulong quotient = Value.FastDiv64(Divisor, FastDivMul);
|
||||||
|
return Value - quotient * Divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod6();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod7UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(7UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 127UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return (ulong)(Value % 7UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod7();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod7UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(7U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 7U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod7();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod7ULongBenchmarks
|
||||||
|
{
|
||||||
|
[Params(7UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 63UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 7UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod7();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod8UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(8UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 255UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return (ulong)(Value % 8UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod8UIntBenchmarks
|
||||||
|
{
|
||||||
|
[Params(8U, 2047U, 65535U, 2147483647U)]
|
||||||
|
public uint Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public uint ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 8U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public uint ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod8ULongBenchmarks
|
||||||
|
{
|
||||||
|
[Params(8UL, 8191UL, 131071UL, 2147483647UL, ulong.MaxValue - 127UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public ulong ModuloOperator()
|
||||||
|
{
|
||||||
|
return Value % 8UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ExtensionMethod()
|
||||||
|
{
|
||||||
|
return Value.Mod8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using BenchmarkDotNet.Running;
|
using BenchmarkDotNet.Running;
|
||||||
|
|
||||||
namespace EvenPerfectBitScanner.Benchmarks;
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ internal static class Program
|
|||||||
RleBlacklist.Load(_rleBlacklistPath!);
|
RleBlacklist.Load(_rleBlacklistPath!);
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong remainder = currentP % 6UL;
|
ulong remainder = currentP.Mod6();
|
||||||
if (currentP == InitialP && string.IsNullOrEmpty(filterFile))
|
if (currentP == InitialP && string.IsNullOrEmpty(filterFile))
|
||||||
{
|
{
|
||||||
// bool passedAllTests = IsEvenPerfectCandidate(InitialP, out bool searchedMersenne, out bool detailedCheck);
|
// bool passedAllTests = IsEvenPerfectCandidate(InitialP, out bool searchedMersenne, out bool detailedCheck);
|
||||||
|
|||||||
@@ -201,6 +201,14 @@ public class UInt128ExtensionsTests
|
|||||||
value.Mod3().Should().Be((ulong)(value % 3));
|
value.Mod3().Should().Be((ulong)(value % 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Mod6_matches_operator()
|
||||||
|
{
|
||||||
|
UInt128 value = (UInt128.One << 100) + 9876543210UL;
|
||||||
|
value.Mod6().Should().Be((ulong)(value % 6));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
public void Mod5_matches_operator()
|
public void Mod5_matches_operator()
|
||||||
|
|||||||
@@ -27,6 +27,17 @@ public class UIntExtensionsTests
|
|||||||
value.Mod5().Should().Be(value % 5U);
|
value.Mod5().Should().Be(value % 5U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod6_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod6().Should().Be(value % 6U);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
[InlineData(0U)]
|
[InlineData(0U)]
|
||||||
|
|||||||
@@ -41,6 +41,16 @@ public class ULongExtensionsTests
|
|||||||
value.Mod5().Should().Be(value % 5UL);
|
value.Mod5().Should().Be(value % 5UL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
public void Mod6_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod6().Should().Be(value % 6UL);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
[InlineData(0UL)]
|
[InlineData(0UL)]
|
||||||
@@ -101,6 +111,22 @@ public class ULongExtensionsTests
|
|||||||
step3.Should().Be(expected3);
|
step3.Should().Be(expected3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(1UL)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
public void Mod11_7_5_3_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod11_7_5_3(out ulong mod11, out ulong mod7, out ulong mod5, out ulong mod3);
|
||||||
|
|
||||||
|
mod11.Should().Be(value % 11UL);
|
||||||
|
mod7.Should().Be(value % 7UL);
|
||||||
|
mod5.Should().Be(value % 5UL);
|
||||||
|
mod3.Should().Be(value % 3UL);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
[InlineData(2UL, true)]
|
[InlineData(2UL, true)]
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ public class MersenneNumberLucasLehmerCpuTester
|
|||||||
// - If p ≡ 1 (mod 4) and p shares a factor with (p-1), reject fast.
|
// - If p ≡ 1 (mod 4) and p shares a factor with (p-1), reject fast.
|
||||||
// - If p is divisible by divisors specific to numbers ending with 1 or 7, reject fast.
|
// - If p is divisible by divisors specific to numbers ending with 1 or 7, reject fast.
|
||||||
if (
|
if (
|
||||||
((exponent % 3UL) == 0UL && exponent != 3UL) ||
|
(exponent.Mod3() == 0UL && exponent != 3UL) ||
|
||||||
((exponent % 5UL) == 0UL && exponent != 5UL) ||
|
(exponent.Mod5() == 0UL && exponent != 5UL) ||
|
||||||
((exponent % 7UL) == 0UL && exponent != 7UL) ||
|
(exponent.Mod7() == 0UL && exponent != 7UL) ||
|
||||||
((exponent % 11UL) == 0UL && exponent != 11UL)
|
(exponent.Mod11() == 0UL && exponent != 11UL)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -200,6 +200,8 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
|
ulong idxMod3 = idx.Mod3();
|
||||||
|
ulong idxMod5 = idx.Mod5();
|
||||||
// residue automaton
|
// residue automaton
|
||||||
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
||||||
ulong r10 = q0m10 + (step10 * idx).Mod10();
|
ulong r10 = q0m10 + (step10 * idx).Mod10();
|
||||||
@@ -215,16 +217,16 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = (exponent.Mod3() << 1).Mod3();
|
||||||
ulong r3 = q0m3 + (step3 * (idx % 3UL)); r3 -= (r3 >= 3UL) ? 3UL : 0UL;
|
ulong r3 = q0m3 + (step3 * idxMod3); r3 -= (r3 >= 3UL) ? 3UL : 0UL;
|
||||||
if (r3 == 0UL)
|
if (r3 == 0UL)
|
||||||
{
|
{
|
||||||
shouldCheck = false;
|
shouldCheck = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong step5Loc = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5Loc = (exponent.Mod5() << 1).Mod5();
|
||||||
ulong r5 = q0m5 + (step5Loc * (idx % 5UL)); if (r5 >= 5UL) r5 -= 5UL;
|
ulong r5 = q0m5 + (step5Loc * idxMod5); if (r5 >= 5UL) r5 -= 5UL;
|
||||||
if (r5 == 0UL)
|
if (r5 == 0UL)
|
||||||
{
|
{
|
||||||
shouldCheck = false;
|
shouldCheck = false;
|
||||||
@@ -358,6 +360,8 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
ArrayView1D<ulong, Stride1D.Dense> smallPrimesPow2LastSeven)
|
ArrayView1D<ulong, Stride1D.Dense> smallPrimesPow2LastSeven)
|
||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
|
ulong idxMod3 = idx.Mod3();
|
||||||
|
ulong idxMod5 = idx.Mod5();
|
||||||
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
||||||
bool shouldCheck = r10 != 5UL;
|
bool shouldCheck = r10 != 5UL;
|
||||||
if (shouldCheck)
|
if (shouldCheck)
|
||||||
@@ -369,7 +373,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong r3 = ra.Q0M3 + (ra.Step3 * (idx % 3UL));
|
ulong r3 = ra.Q0M3 + (ra.Step3 * idxMod3);
|
||||||
if (r3 >= 6UL) r3 -= 6UL;
|
if (r3 >= 6UL) r3 -= 6UL;
|
||||||
if (r3 >= 3UL) r3 -= 3UL;
|
if (r3 >= 3UL) r3 -= 3UL;
|
||||||
if (r3 == 0UL)
|
if (r3 == 0UL)
|
||||||
@@ -378,7 +382,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong r5 = ra.Q0M5 + (ra.Step5 * (idx % 5UL));
|
ulong r5 = ra.Q0M5 + (ra.Step5 * idxMod5);
|
||||||
if (r5 >= 15UL) r5 -= 15UL;
|
if (r5 >= 15UL) r5 -= 15UL;
|
||||||
if (r5 >= 10UL) r5 -= 10UL;
|
if (r5 >= 10UL) r5 -= 10UL;
|
||||||
if (r5 >= 5UL) r5 -= 5UL;
|
if (r5 >= 5UL) r5 -= 5UL;
|
||||||
@@ -489,6 +493,8 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
|
ulong idxMod3 = idx.Mod3();
|
||||||
|
ulong idxMod5 = idx.Mod5();
|
||||||
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
||||||
bool shouldCheck = r10 != 5UL;
|
bool shouldCheck = r10 != 5UL;
|
||||||
if (shouldCheck)
|
if (shouldCheck)
|
||||||
@@ -500,7 +506,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong r3 = ra.Q0M3 + (ra.Step3 * (idx % 3UL));
|
ulong r3 = ra.Q0M3 + (ra.Step3 * idxMod3);
|
||||||
if (r3 >= 6UL) r3 -= 6UL;
|
if (r3 >= 6UL) r3 -= 6UL;
|
||||||
if (r3 >= 3UL) r3 -= 3UL;
|
if (r3 >= 3UL) r3 -= 3UL;
|
||||||
if (r3 == 0UL)
|
if (r3 == 0UL)
|
||||||
@@ -509,7 +515,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong r5 = ra.Q0M5 + (ra.Step5 * (idx % 5UL));
|
ulong r5 = ra.Q0M5 + (ra.Step5 * idxMod5);
|
||||||
if (r5 >= 15UL) r5 -= 15UL;
|
if (r5 >= 15UL) r5 -= 15UL;
|
||||||
if (r5 >= 10UL) r5 -= 10UL;
|
if (r5 >= 10UL) r5 -= 10UL;
|
||||||
if (r5 >= 5UL) r5 -= 5UL;
|
if (r5 >= 5UL) r5 -= 5UL;
|
||||||
@@ -573,6 +579,8 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
|
ulong idxMod3 = idx.Mod3();
|
||||||
|
ulong idxMod5 = idx.Mod5();
|
||||||
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
||||||
bool shouldCheck = r10 != 5UL;
|
bool shouldCheck = r10 != 5UL;
|
||||||
if (shouldCheck)
|
if (shouldCheck)
|
||||||
@@ -584,7 +592,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong r3 = ra.Q0M3 + (ra.Step3 * (idx % 3UL));
|
ulong r3 = ra.Q0M3 + (ra.Step3 * idxMod3);
|
||||||
if (r3 >= 6UL) r3 -= 6UL;
|
if (r3 >= 6UL) r3 -= 6UL;
|
||||||
if (r3 >= 3UL) r3 -= 3UL;
|
if (r3 >= 3UL) r3 -= 3UL;
|
||||||
if (r3 == 0UL)
|
if (r3 == 0UL)
|
||||||
@@ -593,7 +601,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong r5 = ra.Q0M5 + (ra.Step5 * (idx % 5UL));
|
ulong r5 = ra.Q0M5 + (ra.Step5 * idxMod5);
|
||||||
if (r5 >= 15UL) r5 -= 15UL;
|
if (r5 >= 15UL) r5 -= 15UL;
|
||||||
if (r5 >= 10UL) r5 -= 10UL;
|
if (r5 >= 10UL) r5 -= 10UL;
|
||||||
if (r5 >= 5UL) r5 -= 5UL;
|
if (r5 >= 5UL) r5 -= 5UL;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
var incKernel = gpuLease.IncrementalKernel;
|
var incKernel = gpuLease.IncrementalKernel;
|
||||||
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = (exponent.Mod3() << 1).Mod3();
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = (exponent.Mod5() << 1).Mod5();
|
||||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
ResiduePrimeViews primeViews = default;
|
ResiduePrimeViews primeViews = default;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
// Early rejections aligned with incremental/order sieves, but safe for small p:
|
// Early rejections aligned with incremental/order sieves, but safe for small p:
|
||||||
// - If 3 | p and p != 3, then 7 | M_p -> composite.
|
// - If 3 | p and p != 3, then 7 | M_p -> composite.
|
||||||
// - If p ≡ 1 (mod 4) and p shares a factor with (p-1), reject fast.
|
// - If p ≡ 1 (mod 4) and p shares a factor with (p-1), reject fast.
|
||||||
if ((exponent % 3UL) == 0UL && exponent != 3UL)
|
if (exponent.Mod3() == 0UL && exponent != 3UL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -548,7 +548,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int topBits = (int)(exponent % 128UL);
|
int topBits = (int)exponent.Mod128();
|
||||||
if (topBits == 0)
|
if (topBits == 0)
|
||||||
{
|
{
|
||||||
topBits = 128;
|
topBits = 128;
|
||||||
@@ -672,7 +672,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int topBits = (int)(exponent % 128UL);
|
int topBits = (int)exponent.Mod128();
|
||||||
if (topBits == 0)
|
if (topBits == 0)
|
||||||
{
|
{
|
||||||
topBits = 128;
|
topBits = 128;
|
||||||
@@ -803,7 +803,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
vLow.Add(vHigh);
|
vLow.Add(vHigh);
|
||||||
|
|
||||||
// Mask to keep only p low bits and fold the carry bits (v >> p)
|
// Mask to keep only p low bits and fold the carry bits (v >> p)
|
||||||
int topBits = (int)(p % 128UL);
|
int topBits = (int)p.Mod128();
|
||||||
if (topBits == 0)
|
if (topBits == 0)
|
||||||
{
|
{
|
||||||
topBits = 128;
|
topBits = 128;
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
exponent128.Mod10_8_5_3(out ulong exponentMod10, out ulong exponentMod8, out ulong exponentMod5, out ulong exponentMod3);
|
exponent128.Mod10_8_5_3(out ulong exponentMod10, out ulong exponentMod8, out ulong exponentMod5, out ulong exponentMod3);
|
||||||
ulong step10 = (exponentMod10 << 1).Mod10();
|
ulong step10 = (exponentMod10 << 1).Mod10();
|
||||||
ulong step8 = (exponentMod8 << 1) & 7UL;
|
ulong step8 = (exponentMod8 << 1) & 7UL;
|
||||||
ulong step3 = (exponentMod3 << 1) % 3UL;
|
ulong step3 = (exponentMod3 << 1).Mod3();
|
||||||
ulong step5 = (exponentMod5 << 1) % 5UL;
|
ulong step5 = (exponentMod5 << 1).Mod5();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ public class MersenneDivisorCycles
|
|||||||
for (int i = 0; i < localCycleIndex; i++)
|
for (int i = 0; i < localCycleIndex; i++)
|
||||||
{
|
{
|
||||||
(d, cycle) = localCycles[i];
|
(d, cycle) = localCycles[i];
|
||||||
if (d % 3UL == 0UL || d % 5UL == 0UL || d % 7UL == 0UL || d % 11UL == 0UL)
|
if (d.Mod3() == 0UL || d.Mod5() == 0UL || d.Mod7() == 0UL || d.Mod11() == 0UL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
writer.Write(d);
|
writer.Write(d);
|
||||||
@@ -249,7 +249,7 @@ public class MersenneDivisorCycles
|
|||||||
{
|
{
|
||||||
while (skipCount > 0L && start <= maxDivisor)
|
while (skipCount > 0L && start <= maxDivisor)
|
||||||
{
|
{
|
||||||
if ((start & 1UL) == 0UL || start % 3UL == 0UL || start % 5UL == 0UL || start % 7UL == 0UL || start % 11UL == 0UL)
|
if ((start & 1UL) == 0UL || start.Mod3() == 0UL || start.Mod5() == 0UL || start.Mod7() == 0UL || start.Mod11() == 0UL)
|
||||||
{
|
{
|
||||||
start++;
|
start++;
|
||||||
continue;
|
continue;
|
||||||
@@ -296,7 +296,7 @@ public class MersenneDivisorCycles
|
|||||||
{
|
{
|
||||||
d = divisors[i];
|
d = divisors[i];
|
||||||
|
|
||||||
if (d % 3UL == 0UL || d % 5UL == 0UL || d % 7UL == 0UL || d % 11UL == 0UL)
|
if (d.Mod3() == 0UL || d.Mod5() == 0UL || d.Mod7() == 0UL || d.Mod11() == 0UL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
writer.Write(d);
|
writer.Write(d);
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ public sealed class MersenneNumberTester(
|
|||||||
{
|
{
|
||||||
// Safe early rejections using known orders for tiny primes:
|
// Safe early rejections using known orders for tiny primes:
|
||||||
// 7 | M_p iff 3 | p. Avoid rejecting p == 3 where M_3 == 7 is prime.
|
// 7 | M_p iff 3 | p. Avoid rejecting p == 3 where M_3 == 7 is prime.
|
||||||
if ((exponent % 3UL) == 0UL && exponent != 3UL)
|
if (exponent.Mod3() == 0UL && exponent != 3UL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace PerfectNumbers.Core;
|
|
||||||
|
|
||||||
public static class PerfectNumbersMath
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static uint FastRemainder3(uint value)
|
|
||||||
{
|
|
||||||
uint quotient = (uint)(((ulong)value * 0xAAAAAAABUL) >> 33);
|
|
||||||
return value - quotient * 3U;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static uint FastRemainder5(uint value)
|
|
||||||
{
|
|
||||||
uint quotient = (uint)(((ulong)value * 0xCCCCCCCDUL) >> 34);
|
|
||||||
return value - quotient * 5U;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -53,7 +53,7 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else if (n > 5UL && (n % 5UL) == 0UL)
|
else if (n > 5UL && n.Mod5() == 0UL)
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
@@ -260,7 +260,7 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((n & 1UL) == 0UL || (n > 5UL && (n % 5UL) == 0UL))
|
if ((n & 1UL) == 0UL || (n > 5UL && n.Mod5() == 0UL))
|
||||||
{
|
{
|
||||||
results[index] = 0;
|
results[index] = 0;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -100,14 +100,20 @@ public static class PrimesGenerator
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool IsAllowedForLastOne(uint prime)
|
private static bool IsAllowedForLastOne(uint prime)
|
||||||
{
|
{
|
||||||
uint mod10 = prime % 10U;
|
return (prime % 10U) switch
|
||||||
return mod10 == 1U || mod10 == 3U || mod10 == 9U || prime == 7U || prime == 11U;
|
{
|
||||||
|
1U or 3U or 9U => true,
|
||||||
|
_ => prime == 7U || prime == 11U,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool IsAllowedForLastSeven(uint prime)
|
private static bool IsAllowedForLastSeven(uint prime)
|
||||||
{
|
{
|
||||||
uint mod10 = prime % 10U;
|
return (prime % 10U) switch
|
||||||
return mod10 == 3U || mod10 == 7U || mod10 == 9U || prime == 11U;
|
{
|
||||||
|
3U or 7U or 9U => true,
|
||||||
|
_ => prime == 11U,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,23 +123,26 @@ public static class UInt128Extensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Mod10_8_5_3(this UInt128 value, out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3)
|
public static void Mod10_8_5_3(this UInt128 value, out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3)
|
||||||
{
|
{
|
||||||
UInt128 temp = value;
|
UInt128 temp = UInt128.Zero;
|
||||||
uint byteSum = 0U;
|
uint byteSum = 0U;
|
||||||
|
byte current = 0;
|
||||||
|
uint accumulator = 0U;
|
||||||
|
|
||||||
|
temp = value;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
byteSum += (byte)temp;
|
current = (byte)temp;
|
||||||
|
byteSum += current;
|
||||||
temp >>= 8;
|
temp >>= 8;
|
||||||
}
|
}
|
||||||
while (temp != UInt128.Zero);
|
while (temp != UInt128.Zero);
|
||||||
|
|
||||||
mod8 = (ulong)value & 7UL;
|
mod8 = (ulong)value & 7UL;
|
||||||
|
|
||||||
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
accumulator = byteSum.Mod5();
|
||||||
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
mod5 = accumulator;
|
||||||
|
|
||||||
mod10 = (mod8 & 1UL) == 0UL
|
mod10 = (mod8 & 1UL) == 0UL
|
||||||
? mod5Value switch
|
? accumulator switch
|
||||||
{
|
{
|
||||||
0U => 0UL,
|
0U => 0UL,
|
||||||
1U => 6UL,
|
1U => 6UL,
|
||||||
@@ -147,7 +150,7 @@ public static class UInt128Extensions
|
|||||||
3U => 8UL,
|
3U => 8UL,
|
||||||
_ => 4UL,
|
_ => 4UL,
|
||||||
}
|
}
|
||||||
: mod5Value switch
|
: accumulator switch
|
||||||
{
|
{
|
||||||
0U => 5UL,
|
0U => 5UL,
|
||||||
1U => 1UL,
|
1U => 1UL,
|
||||||
@@ -156,8 +159,9 @@ public static class UInt128Extensions
|
|||||||
_ => 9UL,
|
_ => 9UL,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod5 = mod5Value;
|
// Reusing accumulator to hold the mod 3 reduction now that the mod 5 value has been stored.
|
||||||
mod3 = mod3Value;
|
accumulator = byteSum.Mod3();
|
||||||
|
mod3 = accumulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -238,6 +242,20 @@ public static class UInt128Extensions
|
|||||||
return remainder >= 5UL ? remainder - 5UL : remainder;
|
return remainder >= 5UL ? remainder - 5UL : remainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod6(this UInt128 value)
|
||||||
|
{
|
||||||
|
return ((value.Mod3() << 1) | ((ulong)value & 1UL)) switch
|
||||||
|
{
|
||||||
|
0UL => 0UL,
|
||||||
|
1UL => 3UL,
|
||||||
|
2UL => 4UL,
|
||||||
|
3UL => 1UL,
|
||||||
|
4UL => 2UL,
|
||||||
|
_ => 5UL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod7(this UInt128 value)
|
public static ulong Mod7(this UInt128 value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,21 +4,54 @@ namespace PerfectNumbers.Core;
|
|||||||
|
|
||||||
public static class UIntExtensions
|
public static class UIntExtensions
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
private static readonly byte[] Mod6Lookup = { 0, 3, 4, 1, 2, 5 };
|
||||||
public static uint Mod3(this uint value) => PerfectNumbersMath.FastRemainder3(value);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint Mod5(this uint value) => PerfectNumbersMath.FastRemainder5(value);
|
public static uint Mod3(this uint value)
|
||||||
|
{
|
||||||
|
ulong wideValue = 0UL;
|
||||||
|
uint quotient = 0U;
|
||||||
|
uint remainder = 0U;
|
||||||
|
|
||||||
|
wideValue = (ulong)value * 0xAAAAAAABUL;
|
||||||
|
quotient = (uint)(wideValue >> 33);
|
||||||
|
remainder = value - quotient * 3U;
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod5(this uint value)
|
||||||
|
{
|
||||||
|
ulong wideValue = 0UL;
|
||||||
|
uint quotient = 0U;
|
||||||
|
uint remainder = 0U;
|
||||||
|
|
||||||
|
wideValue = (ulong)value * 0xCCCCCCCDUL;
|
||||||
|
quotient = (uint)(wideValue >> 34);
|
||||||
|
remainder = value - quotient * 5U;
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod6(this uint value)
|
||||||
|
{
|
||||||
|
return Mod6Lookup[(int)(((value.Mod3() << 1) | (value & 1U)))];
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint Mod7(this uint value)
|
public static uint Mod7(this uint value)
|
||||||
{
|
{
|
||||||
uint remainder = 0U;
|
uint remainder = 0U;
|
||||||
uint temp = value;
|
uint temp = 0U;
|
||||||
|
uint chunk = 0U;
|
||||||
|
|
||||||
|
temp = value;
|
||||||
while (temp != 0U)
|
while (temp != 0U)
|
||||||
{
|
{
|
||||||
remainder += temp & 7U;
|
chunk = temp & 7U;
|
||||||
|
remainder += chunk;
|
||||||
temp >>= 3;
|
temp >>= 3;
|
||||||
if (remainder >= 7U)
|
if (remainder >= 7U)
|
||||||
{
|
{
|
||||||
@@ -35,18 +68,29 @@ public static class UIntExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint Mod10(this uint value)
|
public static uint Mod10(this uint value)
|
||||||
{
|
{
|
||||||
return value - (uint)(((ulong)value * 0xCCCCCCCDUL) >> 35) * 10U;
|
ulong wideValue = 0UL;
|
||||||
|
uint quotient = 0U;
|
||||||
|
uint remainder = 0U;
|
||||||
|
|
||||||
|
wideValue = (ulong)value * 0xCCCCCCCDUL;
|
||||||
|
quotient = (uint)(wideValue >> 35);
|
||||||
|
remainder = value - quotient * 10U;
|
||||||
|
|
||||||
|
return remainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint Mod11(this uint value)
|
public static uint Mod11(this uint value)
|
||||||
{
|
{
|
||||||
uint remainder = 0U;
|
uint remainder = 0U;
|
||||||
uint temp = value;
|
uint temp = 0U;
|
||||||
|
uint chunk = 0U;
|
||||||
|
|
||||||
|
temp = value;
|
||||||
while (temp != 0U)
|
while (temp != 0U)
|
||||||
{
|
{
|
||||||
remainder += temp & 1023U;
|
chunk = temp & 1023U;
|
||||||
|
remainder += chunk;
|
||||||
temp >>= 10;
|
temp >>= 10;
|
||||||
remainder -= 11U * (remainder / 11U);
|
remainder -= 11U * (remainder / 11U);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,26 +57,33 @@ public static class ULongExtensions
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly byte[] Mod6Lookup = { 0, 3, 4, 1, 2, 5 };
|
||||||
|
private static readonly byte[] Mod7ByteCoefficients = { 1, 4, 2, 1, 4, 2, 1, 4 };
|
||||||
|
private static readonly byte[] Mod11ByteCoefficients = { 1, 3, 9, 5, 4, 1, 3, 9 };
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Mod10_8_5_3(this ulong value, out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3)
|
public static void Mod10_8_5_3(this ulong value, out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3)
|
||||||
{
|
{
|
||||||
ulong temp = value;
|
ulong temp = 0UL;
|
||||||
uint byteSum = 0U;
|
uint byteSum = 0U;
|
||||||
|
byte current = 0;
|
||||||
|
uint accumulator = 0U;
|
||||||
|
|
||||||
|
temp = value;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
byteSum += (byte)temp;
|
current = (byte)temp;
|
||||||
|
byteSum += current;
|
||||||
temp >>= 8;
|
temp >>= 8;
|
||||||
}
|
}
|
||||||
while (temp != 0UL);
|
while (temp != 0UL);
|
||||||
|
|
||||||
mod8 = value & 7UL;
|
mod8 = value & 7UL;
|
||||||
|
|
||||||
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
accumulator = byteSum.Mod5();
|
||||||
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
mod5 = accumulator;
|
||||||
|
|
||||||
mod10 = (mod8 & 1UL) == 0UL
|
mod10 = (mod8 & 1UL) == 0UL
|
||||||
? mod5Value switch
|
? accumulator switch
|
||||||
{
|
{
|
||||||
0U => 0UL,
|
0U => 0UL,
|
||||||
1U => 6UL,
|
1U => 6UL,
|
||||||
@@ -84,7 +91,7 @@ public static class ULongExtensions
|
|||||||
3U => 8UL,
|
3U => 8UL,
|
||||||
_ => 4UL,
|
_ => 4UL,
|
||||||
}
|
}
|
||||||
: mod5Value switch
|
: accumulator switch
|
||||||
{
|
{
|
||||||
0U => 5UL,
|
0U => 5UL,
|
||||||
1U => 1UL,
|
1U => 1UL,
|
||||||
@@ -93,14 +100,60 @@ public static class ULongExtensions
|
|||||||
_ => 9UL,
|
_ => 9UL,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod5 = mod5Value;
|
// Reusing accumulator to hold the mod 3 reduction now that the mod 5 value has been stored.
|
||||||
mod3 = mod3Value;
|
accumulator = byteSum.Mod3();
|
||||||
|
mod3 = accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Mod11_7_5_3(this ulong value, out ulong mod11, out ulong mod7, out ulong mod5, out ulong mod3)
|
||||||
|
{
|
||||||
|
uint mod3Accumulator = 0U;
|
||||||
|
uint mod5Accumulator = 0U;
|
||||||
|
uint mod7Accumulator = 0U;
|
||||||
|
uint mod11Accumulator = 0U;
|
||||||
|
ulong temp = 0UL;
|
||||||
|
int index = 0;
|
||||||
|
byte current = 0;
|
||||||
|
|
||||||
|
temp = value;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
current = (byte)temp;
|
||||||
|
mod3Accumulator += current;
|
||||||
|
mod5Accumulator += current;
|
||||||
|
mod7Accumulator += (uint)(current * Mod7ByteCoefficients[index]);
|
||||||
|
mod11Accumulator += (uint)(current * Mod11ByteCoefficients[index]);
|
||||||
|
|
||||||
|
temp >>= 8;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
while (temp != 0UL);
|
||||||
|
|
||||||
|
// Reusing mod3Accumulator to store the reduced mod 3 remainder before exposing it.
|
||||||
|
mod3Accumulator = mod3Accumulator.Mod3();
|
||||||
|
// Reusing mod5Accumulator to store the reduced mod 5 remainder before exposing it.
|
||||||
|
mod5Accumulator = mod5Accumulator.Mod5();
|
||||||
|
// Reusing mod7Accumulator to store the reduced mod 7 remainder before exposing it.
|
||||||
|
mod7Accumulator = (uint)ReduceMod7(mod7Accumulator);
|
||||||
|
// Reusing mod11Accumulator to store the reduced mod 11 remainder before exposing it.
|
||||||
|
mod11Accumulator = (uint)ReduceMod11(mod11Accumulator);
|
||||||
|
|
||||||
|
mod3 = mod3Accumulator;
|
||||||
|
mod5 = mod5Accumulator;
|
||||||
|
mod7 = mod7Accumulator;
|
||||||
|
mod11 = mod11Accumulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Mod10_8_5_3Steps(this ulong value, out ulong step10, out ulong step8, out ulong step5, out ulong step3)
|
public static void Mod10_8_5_3Steps(this ulong value, out ulong step10, out ulong step8, out ulong step5, out ulong step3)
|
||||||
{
|
{
|
||||||
value.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
ulong mod10 = 0UL;
|
||||||
|
ulong mod8 = 0UL;
|
||||||
|
ulong mod5 = 0UL;
|
||||||
|
ulong mod3 = 0UL;
|
||||||
|
|
||||||
|
value.Mod10_8_5_3(out mod10, out mod8, out mod5, out mod3);
|
||||||
|
|
||||||
step10 = (mod10 << 1).Mod10();
|
step10 = (mod10 << 1).Mod10();
|
||||||
step8 = ((mod8 << 1) & 7UL);
|
step8 = ((mod8 << 1) & 7UL);
|
||||||
@@ -112,7 +165,7 @@ public static class ULongExtensions
|
|||||||
public static bool IsPrimeCandidate(this ulong n)
|
public static bool IsPrimeCandidate(this ulong n)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ulong p;
|
ulong p = 0UL;
|
||||||
uint[] smallPrimes = PrimesGenerator.SmallPrimes;
|
uint[] smallPrimes = PrimesGenerator.SmallPrimes;
|
||||||
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
|
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
|
||||||
int len = smallPrimes.Length;
|
int len = smallPrimes.Length;
|
||||||
@@ -136,11 +189,14 @@ public static class ULongExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod10(this ulong value)
|
public static ulong Mod10(this ulong value)
|
||||||
{
|
{
|
||||||
ulong mod5 = value.Mod5();
|
ulong mod5 = 0UL;
|
||||||
|
ulong result = 0UL;
|
||||||
|
|
||||||
|
mod5 = value.Mod5();
|
||||||
|
|
||||||
if ((value & 1UL) == 0UL)
|
if ((value & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
return mod5 switch
|
result = mod5 switch
|
||||||
{
|
{
|
||||||
0UL => 0UL,
|
0UL => 0UL,
|
||||||
1UL => 6UL,
|
1UL => 6UL,
|
||||||
@@ -149,8 +205,9 @@ public static class ULongExtensions
|
|||||||
_ => 4UL,
|
_ => 4UL,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
else
|
||||||
return mod5 switch
|
{
|
||||||
|
result = mod5 switch
|
||||||
{
|
{
|
||||||
0UL => 5UL,
|
0UL => 5UL,
|
||||||
1UL => 1UL,
|
1UL => 1UL,
|
||||||
@@ -160,38 +217,65 @@ public static class ULongExtensions
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod8(this ulong value) => value & 7UL;
|
public static ulong Mod8(this ulong value) => value & 7UL;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod3(this ulong value)
|
public static ulong Mod3(this ulong value)
|
||||||
{
|
{
|
||||||
uint sum = (uint)(value & 0xFFFFUL);
|
uint sum = 0U;
|
||||||
sum += (uint)((value >> 16) & 0xFFFFUL);
|
ulong temp = 0UL;
|
||||||
sum += (uint)((value >> 32) & 0xFFFFUL);
|
|
||||||
sum += (uint)((value >> 48) & 0xFFFFUL);
|
|
||||||
|
|
||||||
return PerfectNumbersMath.FastRemainder3(sum);
|
temp = value & 0xFFFFUL;
|
||||||
|
sum = (uint)temp;
|
||||||
|
temp = (value >> 16) & 0xFFFFUL;
|
||||||
|
sum += (uint)temp;
|
||||||
|
temp = (value >> 32) & 0xFFFFUL;
|
||||||
|
sum += (uint)temp;
|
||||||
|
temp = (value >> 48) & 0xFFFFUL;
|
||||||
|
sum += (uint)temp;
|
||||||
|
|
||||||
|
return sum.Mod3();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod5(this ulong value)
|
public static ulong Mod5(this ulong value)
|
||||||
{
|
{
|
||||||
uint sum = (uint)(value & 0xFFFFUL);
|
uint sum = 0U;
|
||||||
sum += (uint)((value >> 16) & 0xFFFFUL);
|
ulong temp = 0UL;
|
||||||
sum += (uint)((value >> 32) & 0xFFFFUL);
|
|
||||||
sum += (uint)((value >> 48) & 0xFFFFUL);
|
|
||||||
|
|
||||||
return PerfectNumbersMath.FastRemainder5(sum);
|
temp = value & 0xFFFFUL;
|
||||||
|
sum = (uint)temp;
|
||||||
|
temp = (value >> 16) & 0xFFFFUL;
|
||||||
|
sum += (uint)temp;
|
||||||
|
temp = (value >> 32) & 0xFFFFUL;
|
||||||
|
sum += (uint)temp;
|
||||||
|
temp = (value >> 48) & 0xFFFFUL;
|
||||||
|
sum += (uint)temp;
|
||||||
|
|
||||||
|
return sum.Mod5();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod6(this ulong value)
|
||||||
|
{
|
||||||
|
return Mod6Lookup[(int)(((value.Mod3() << 1) | (value & 1UL)))];
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod7(this ulong value)
|
public static ulong Mod7(this ulong value)
|
||||||
{
|
{
|
||||||
uint low = (uint)value;
|
uint low = 0U;
|
||||||
uint high = (uint)(value >> 32);
|
uint high = 0U;
|
||||||
|
ulong remainder = 0UL;
|
||||||
|
|
||||||
ulong remainder = low.Mod7() + (ulong)high.Mod7() * 4UL;
|
low = (uint)value;
|
||||||
|
high = (uint)(value >> 32);
|
||||||
|
|
||||||
|
remainder = low.Mod7() + (ulong)high.Mod7() * 4UL;
|
||||||
while (remainder >= 7UL)
|
while (remainder >= 7UL)
|
||||||
{
|
{
|
||||||
remainder -= 7UL;
|
remainder -= 7UL;
|
||||||
@@ -203,10 +287,14 @@ public static class ULongExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod11(this ulong value)
|
public static ulong Mod11(this ulong value)
|
||||||
{
|
{
|
||||||
uint low = (uint)value;
|
uint low = 0U;
|
||||||
uint high = (uint)(value >> 32);
|
uint high = 0U;
|
||||||
|
ulong remainder = 0UL;
|
||||||
|
|
||||||
ulong remainder = low.Mod11() + (ulong)high.Mod11() * 4UL;
|
low = (uint)value;
|
||||||
|
high = (uint)(value >> 32);
|
||||||
|
|
||||||
|
remainder = low.Mod11() + (ulong)high.Mod11() * 4UL;
|
||||||
while (remainder >= 11UL)
|
while (remainder >= 11UL)
|
||||||
{
|
{
|
||||||
remainder -= 11UL;
|
remainder -= 11UL;
|
||||||
@@ -218,6 +306,36 @@ public static class ULongExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod128(this ulong value) => value & 127UL;
|
public static ulong Mod128(this ulong value) => value & 127UL;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static ulong ReduceMod7(uint value)
|
||||||
|
{
|
||||||
|
while (value >= 7U)
|
||||||
|
{
|
||||||
|
value = (value >> 3) + (value & 7U);
|
||||||
|
if (value >= 7U && value < 14U)
|
||||||
|
{
|
||||||
|
value -= 7U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static ulong ReduceMod11(uint value)
|
||||||
|
{
|
||||||
|
while (value >= 11U)
|
||||||
|
{
|
||||||
|
value = (value & 15U) + ((value >> 4) * 5U);
|
||||||
|
if (value >= 11U && value < 22U)
|
||||||
|
{
|
||||||
|
value -= 11U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static UInt128 Mul64(this ulong a, ulong b) => ((UInt128)a.MulHigh(b) << 64) | (UInt128)(a * b);
|
public static UInt128 Mul64(this ulong a, ulong b) => ((UInt128)a.MulHigh(b) << 64) | (UInt128)(a * b);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user