diff --git a/EvenPerfectBitScanner.Benchmarks/Mod10_8_5_3PropertiesBenchmarks.cs b/EvenPerfectBitScanner.Benchmarks/Mod10_8_5_3PropertiesBenchmarks.cs new file mode 100644 index 0000000..b3924e6 --- /dev/null +++ b/EvenPerfectBitScanner.Benchmarks/Mod10_8_5_3PropertiesBenchmarks.cs @@ -0,0 +1,65 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using BenchmarkDotNet.Attributes; +using PerfectNumbers.Core; + +namespace EvenPerfectBitScanner.Benchmarks; + +[MemoryDiagnoser] +public class Mod10_8_5_3PropertiesBenchmarks +{ + public ulong Mod10R; + public ulong Mod8R; + public ulong Mod3R; + public ulong Mod5R; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Mod8(UInt128 value) => (ulong)value & 7UL; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Mod3(UInt128 value) + { + // 2^64 ≡ 1 (mod 3) + ulong high = (ulong)(value >> 64); + ulong low = (ulong)value; + ulong rem = (low % 3UL) + (high % 3UL); + return rem >= 3UL ? rem - 3UL : rem; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Mod5(UInt128 value) + { + // 2^64 ≡ 1 (mod 5) + ulong high = (ulong)(value >> 64); + ulong low = (ulong)value; + ulong rem = (low % 5UL) + (high % 5UL); + return rem >= 5UL ? rem - 5UL : rem; + } + + [Params(3UL, 8191UL, 131071UL, 2147483647UL)] + public ulong Value { get; set; } + + [Benchmark(Baseline = true)] + public (ulong Mod10, ulong Mod8, ulong Mod5, ulong Mod3) LegacyModulo() + { + UInt128 value = Value; + Mod10R = value.Mod10(); + Mod8R = Mod8(value); + Mod5R = Mod5(value); + Mod3R = Mod3(value); + return (Mod10R, Mod8R, Mod5R, Mod3R); + } + + [Benchmark] + public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) ModMethodModulo() + { + Value.Mod10_8_5_3(out var mod10, out ulong mod8, out ulong mod5, out ulong mod3); + Mod10R = mod10; + Mod8R = mod8; + Mod5R = mod5; + Mod3R = mod3; + + return (Mod10R, Mod8R, Mod3R, Mod5R); + } +} + diff --git a/PerfectNumbers.Core/ModuloAutomata.cs b/PerfectNumbers.Core/ModuloAutomata.cs index b264cd6..1910555 100644 --- a/PerfectNumbers.Core/ModuloAutomata.cs +++ b/PerfectNumbers.Core/ModuloAutomata.cs @@ -12,11 +12,11 @@ public sealed class MersenneResidueAutomaton private readonly UInt128 _step; // 2*p private UInt128 _currentQ; // current q value - // Cached residues for current q - public ulong Mod10R { get; private set; } - public ulong Mod8R { get; private set; } - public ulong Mod3R { get; private set; } - public ulong Mod5R { get; private set; } + // Cached residues for current q + public ulong Mod10R; + public ulong Mod8R; + public ulong Mod3R; + public ulong Mod5R; // Cached residues for step (2*p mod m) private readonly ulong _step10; @@ -27,18 +27,18 @@ public sealed class MersenneResidueAutomaton public MersenneResidueAutomaton(ulong exponent) { _step = (UInt128)exponent << 1; // 2 * p - _currentQ = _step + 1UL; // start at k = 1 + _currentQ = _step + UInt128.One; // start at k = 1 - // init residues + // init residues Mod10R = _currentQ.Mod10(); - Mod8R = Mod8(_currentQ); - Mod3R = Mod3(_currentQ); - Mod5R = Mod5(_currentQ); + Mod8R = _currentQ.Mod8(); + Mod3R = _currentQ.Mod3(); + Mod5R = _currentQ.Mod5(); _step10 = _step.Mod10().Mod10(); - _step8 = (ulong)(_step & 7UL); // % 8 - _step3 = Mod3(_step); - _step5 = Mod5(_step); + _step8 = _step.Mod8(); + _step3 = _step.Mod3(); + _step5 = _step.Mod5(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -71,29 +71,6 @@ public sealed class MersenneResidueAutomaton } Mod5R = r5; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Mod8(UInt128 value) => (ulong)value & 7UL; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Mod3(UInt128 value) - { - // 2^64 ≡ 1 (mod 3) - ulong high = (ulong)(value >> 64); - ulong low = (ulong)value; - ulong rem = (low % 3UL) + (high % 3UL); - return rem >= 3UL ? rem - 3UL : rem; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Mod5(UInt128 value) - { - // 2^64 ≡ 1 (mod 5) - ulong high = (ulong)(value >> 64); - ulong low = (ulong)value; - ulong rem = (low % 5UL) + (high % 5UL); - return rem >= 5UL ? rem - 5UL : rem; - } } /// diff --git a/PerfectNumbers.Core/UInt128Extensions.cs b/PerfectNumbers.Core/UInt128Extensions.cs index 5a375b9..2b31094 100644 --- a/PerfectNumbers.Core/UInt128Extensions.cs +++ b/PerfectNumbers.Core/UInt128Extensions.cs @@ -224,7 +224,7 @@ public static class UInt128Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Mod8(this UInt128 value) => (ulong)value & 7UL; - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Mod3(this UInt128 value) { @@ -241,6 +241,7 @@ public static class UInt128Extensions return rem >= 5UL ? rem - 5UL : rem; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static UInt128 Mul64(this UInt128 a, UInt128 b) {