Benchmarks extended. Small optimizations.
This commit is contained in:
1 parent
53554ffd3d
commit
1499f6abe1
5 files changed
+180
-78
No files matched your search
@@ -24,13 +24,12 @@ public class ResidueComputationBenchmarks
|
|||||||
[Benchmark]
|
[Benchmark]
|
||||||
public (ulong Step10, ulong Step8, ulong Step3, ulong Step5) ModMethodModulo()
|
public (ulong Step10, ulong Step8, ulong Step3, ulong Step5) ModMethodModulo()
|
||||||
{
|
{
|
||||||
UInt128 exponent128 = Exponent;
|
Exponent.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
||||||
exponent128.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
mod10 = (mod10 << 1) % 10UL;
|
||||||
ulong step10 = (mod10 << 1) % 10UL;
|
mod8 = (mod8 << 1) & 7UL;
|
||||||
ulong step8 = (mod8 << 1) & 7UL;
|
mod3 = (mod3 << 1) % 3UL;
|
||||||
ulong step3 = (mod3 << 1) % 3UL;
|
mod5 = (mod5 << 1) % 5UL;
|
||||||
ulong step5 = (mod5 << 1) % 5UL;
|
return (mod10, mod8, mod3, mod5);
|
||||||
return (step10, step8, step3, step5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class UInt128ExtensionsBenchmarks
|
||||||
|
{
|
||||||
|
[Params(3UL, 8191UL, 131071UL, 2147483647UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) LegacyModulo()
|
||||||
|
{
|
||||||
|
ulong mod10, mod8, mod3, mod5;
|
||||||
|
UInt128 zero = UInt128.Zero;
|
||||||
|
if (Value == zero)
|
||||||
|
{
|
||||||
|
mod3 = 0UL;
|
||||||
|
mod5 = 0UL;
|
||||||
|
mod8 = 0UL;
|
||||||
|
mod10 = 0UL;
|
||||||
|
return (mod10, mod8, mod3, mod5);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt128 high = Value >> 64;
|
||||||
|
ulong result = Value;
|
||||||
|
mod8 = result & 7UL;
|
||||||
|
// 2^64 ≡ 1 (mod 3)
|
||||||
|
ulong modRem = (result % 3UL) + ((ulong)high % 3UL);
|
||||||
|
mod3 = modRem >= 3UL ? modRem - 3UL : modRem;
|
||||||
|
// 2^64 ≡ 1 (mod 5)
|
||||||
|
modRem = (result % 5UL) + ((ulong)high % 5UL);
|
||||||
|
mod5 = modRem >= 5UL ? modRem - 5UL : modRem;
|
||||||
|
|
||||||
|
while (high != zero)
|
||||||
|
{
|
||||||
|
// 2^64 ≡ 6 (mod 10)
|
||||||
|
result = (result + (ulong)high * 6UL) % 10UL;
|
||||||
|
high >>= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod10 = result % 10UL;
|
||||||
|
return (mod10, mod8, mod3, mod5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) ModMethodModulo()
|
||||||
|
{
|
||||||
|
Value.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
||||||
|
return (mod10, mod8, mod3, mod5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -120,87 +120,73 @@ public static class UInt128Extensions
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[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 = value;
|
||||||
uint byteSum = 0U;
|
uint byteSum = 0U;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
byteSum += (uint)(byte)temp;
|
byteSum += (byte)temp;
|
||||||
temp >>= 8;
|
temp >>= 8;
|
||||||
}
|
}
|
||||||
while (temp != UInt128.Zero);
|
while (temp != UInt128.Zero);
|
||||||
|
|
||||||
mod8 = (ulong)value & 7UL;
|
mod8 = (ulong)value & 7UL;
|
||||||
|
|
||||||
uint mod5Value = FastRemainder5(byteSum);
|
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
||||||
uint mod3Value = FastRemainder3(byteSum);
|
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
||||||
|
|
||||||
ulong parity = mod8 & 1UL;
|
ulong parity = mod8 & 1UL;
|
||||||
mod10 = parity == 0UL
|
mod10 = parity == 0UL
|
||||||
? mod5Value switch
|
? mod5Value switch
|
||||||
{
|
{
|
||||||
0U => 0UL,
|
0U => 0UL,
|
||||||
1U => 6UL,
|
1U => 6UL,
|
||||||
2U => 2UL,
|
2U => 2UL,
|
||||||
3U => 8UL,
|
3U => 8UL,
|
||||||
_ => 4UL,
|
_ => 4UL,
|
||||||
}
|
}
|
||||||
: mod5Value switch
|
: mod5Value switch
|
||||||
{
|
{
|
||||||
0U => 5UL,
|
0U => 5UL,
|
||||||
1U => 1UL,
|
1U => 1UL,
|
||||||
2U => 7UL,
|
2U => 7UL,
|
||||||
3U => 3UL,
|
3U => 3UL,
|
||||||
_ => 9UL,
|
_ => 9UL,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod5 = mod5Value;
|
mod5 = mod5Value;
|
||||||
mod3 = mod3Value;
|
mod3 = mod3Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static uint FastRemainder3(uint value)
|
public static UInt128 Pow(this UInt128 value, ulong exponent)
|
||||||
{
|
{
|
||||||
uint quotient = (uint)(((ulong)value * 0xAAAAAAABUL) >> 33);
|
UInt128 result = UInt128.One;
|
||||||
return value - quotient * 3U;
|
UInt128 baseValue = value;
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
while (exponent != 0UL)
|
||||||
private static uint FastRemainder5(uint value)
|
{
|
||||||
{
|
if ((exponent & 1UL) != 0UL)
|
||||||
uint quotient = (uint)(((ulong)value * 0xCCCCCCCDUL) >> 34);
|
{
|
||||||
return value - quotient * 5U;
|
result *= baseValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
baseValue *= baseValue;
|
||||||
public static UInt128 Pow(this UInt128 value, ulong exponent)
|
exponent >>= 1;
|
||||||
{
|
}
|
||||||
UInt128 result = UInt128.One;
|
|
||||||
UInt128 baseValue = value;
|
|
||||||
|
|
||||||
while (exponent != 0UL)
|
return result;
|
||||||
{
|
}
|
||||||
if ((exponent & 1UL) != 0UL)
|
|
||||||
{
|
|
||||||
result *= baseValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
baseValue *= baseValue;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
exponent >>= 1;
|
public static UInt128 ModPow(this UInt128 value, UInt128 exponent, UInt128 modulus)
|
||||||
}
|
{
|
||||||
|
UInt128 result, one = result = UInt128.One,
|
||||||
return result;
|
zero = UInt128.Zero,
|
||||||
}
|
baseValue = value % modulus;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static UInt128 ModPow(this UInt128 value, UInt128 exponent, UInt128 modulus)
|
|
||||||
{
|
|
||||||
UInt128 result, one = result = UInt128.One,
|
|
||||||
zero = UInt128.Zero,
|
|
||||||
baseValue = value % modulus;
|
|
||||||
|
|
||||||
while (exponent != zero)
|
while (exponent != zero)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,6 +57,47 @@ public static class ULongExtensions
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[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)
|
||||||
|
{
|
||||||
|
ulong temp = value;
|
||||||
|
uint byteSum = 0U;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byteSum += (byte)temp;
|
||||||
|
temp >>= 8;
|
||||||
|
}
|
||||||
|
while (temp != 0UL);
|
||||||
|
|
||||||
|
mod8 = value & 7UL;
|
||||||
|
|
||||||
|
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
||||||
|
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
||||||
|
|
||||||
|
ulong parity = mod8 & 1UL;
|
||||||
|
mod10 = parity == 0UL
|
||||||
|
? mod5Value switch
|
||||||
|
{
|
||||||
|
0U => 0UL,
|
||||||
|
1U => 6UL,
|
||||||
|
2U => 2UL,
|
||||||
|
3U => 8UL,
|
||||||
|
_ => 4UL,
|
||||||
|
}
|
||||||
|
: mod5Value switch
|
||||||
|
{
|
||||||
|
0U => 5UL,
|
||||||
|
1U => 1UL,
|
||||||
|
2U => 7UL,
|
||||||
|
3U => 3UL,
|
||||||
|
_ => 9UL,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod5 = mod5Value;
|
||||||
|
mod3 = mod3Value;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsPrimeCandidate(this ulong n)
|
public static bool IsPrimeCandidate(this ulong n)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user