Merge pull request #53 from mlemanczyk/codex/add-mod3,-mod5,-mod7,-mod8,-mod10-methods
Add optimized modulo helpers and update GPU residue steps
This commit is contained in:
7 files changed
+351
-10
No files matched your search
@@ -209,6 +209,30 @@ public class UInt128ExtensionsTests
|
|||||||
value.Mod5().Should().Be((ulong)(value % 5));
|
value.Mod5().Should().Be((ulong)(value % 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Mod7_matches_operator()
|
||||||
|
{
|
||||||
|
UInt128 value = (UInt128.One << 100) + 9876543210987654321UL;
|
||||||
|
value.Mod7().Should().Be((ulong)(value % 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Mod11_matches_operator()
|
||||||
|
{
|
||||||
|
UInt128 value = (UInt128.One << 120) + 9876543210987654321UL;
|
||||||
|
value.Mod11().Should().Be((ulong)(value % 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Mod128_matches_operator()
|
||||||
|
{
|
||||||
|
UInt128 value = (UInt128.One << 120) + 9876543210987654321UL;
|
||||||
|
value.Mod128().Should().Be((ulong)(value % 128));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
public void Mul64_matches_expected_product()
|
public void Mul64_matches_expected_product()
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace PerfectNumbers.Core.Tests;
|
||||||
|
|
||||||
|
public class UIntExtensionsTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod3_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod3().Should().Be(value % 3U);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod5_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod5().Should().Be(value % 5U);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod7_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod7().Should().Be(value % 7U);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod8_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod8().Should().Be(value % 8U);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod10_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod10().Should().Be(value % 10U);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod11_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod11().Should().Be(value % 11U);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0U)]
|
||||||
|
[InlineData(1U)]
|
||||||
|
[InlineData(1234567890U)]
|
||||||
|
[InlineData(uint.MaxValue)]
|
||||||
|
public void Mod128_matches_operator(uint value)
|
||||||
|
{
|
||||||
|
value.Mod128().Should().Be(value % 128U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -21,6 +21,86 @@ public class ULongExtensionsTests
|
|||||||
ULongExtensions.Mod10(value).Should().Be(expected);
|
ULongExtensions.Mod10(value).Should().Be(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
public void Mod3_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod3().Should().Be(value % 3UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
public void Mod5_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod5().Should().Be(value % 5UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
public void Mod7_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod7().Should().Be(value % 7UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
public void Mod8_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod8().Should().Be(value % 8UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
public void Mod11_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod11().Should().Be(value % 11UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(0UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
[InlineData(1234567890123456789UL)]
|
||||||
|
public void Mod128_matches_operator(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod128().Should().Be(value % 128UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
[InlineData(1UL)]
|
||||||
|
[InlineData(123456789UL)]
|
||||||
|
[InlineData(ulong.MaxValue)]
|
||||||
|
public void Mod10_8_5_3Steps_matches_manual_formula(ulong value)
|
||||||
|
{
|
||||||
|
value.Mod10_8_5_3Steps(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
|
||||||
|
|
||||||
|
ulong expected10 = ((value % 10UL) << 1) % 10UL;
|
||||||
|
ulong expected8 = ((value & 7UL) << 1) & 7UL;
|
||||||
|
ulong expected5 = ((value % 5UL) << 1) % 5UL;
|
||||||
|
ulong expected3 = ((value % 3UL) << 1) % 3UL;
|
||||||
|
|
||||||
|
step10.Should().Be(expected10);
|
||||||
|
step8.Should().Be(expected8);
|
||||||
|
step5.Should().Be(expected5);
|
||||||
|
step3.Should().Be(expected3);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
[InlineData(2UL, true)]
|
[InlineData(2UL, true)]
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
UInt128 kStart = 1UL;
|
UInt128 kStart = 1UL;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||||
var kernel = gpuLease.Pow2ModKernel;
|
var kernel = gpuLease.Pow2ModKernel;
|
||||||
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
exponent.Mod10_8_5_3Steps(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
|
||||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||||
|
|
||||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||||
|
|||||||
@@ -228,19 +228,44 @@ public static class UInt128Extensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod3(this UInt128 value)
|
public static ulong Mod3(this UInt128 value)
|
||||||
{
|
{
|
||||||
// 2^64 ≡ 1 (mod 3)
|
ulong remainder = ((ulong)value).Mod3() + ((ulong)(value >> 64)).Mod3();
|
||||||
ulong rem = ((ulong)value % 3UL) + ((ulong)(value >> 64) % 3UL);
|
return remainder >= 3UL ? remainder - 3UL : remainder;
|
||||||
return rem >= 3UL ? rem - 3UL : rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Mod5(this UInt128 value)
|
public static ulong Mod5(this UInt128 value)
|
||||||
{
|
{
|
||||||
// 2^64 ≡ 1 (mod 5)
|
ulong remainder = ((ulong)value).Mod5() + ((ulong)(value >> 64)).Mod5();
|
||||||
ulong rem = ((ulong)value % 5UL) + ((ulong)(value >> 64) % 5UL);
|
return remainder >= 5UL ? remainder - 5UL : remainder;
|
||||||
return rem >= 5UL ? rem - 5UL : rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod7(this UInt128 value)
|
||||||
|
{
|
||||||
|
ulong remainder = ((ulong)value).Mod7() + ((ulong)(value >> 64)).Mod7() * 2UL;
|
||||||
|
while (remainder >= 7UL)
|
||||||
|
{
|
||||||
|
remainder -= 7UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod11(this UInt128 value)
|
||||||
|
{
|
||||||
|
ulong remainder = ((ulong)value).Mod11() + ((ulong)(value >> 64)).Mod11() * 5UL;
|
||||||
|
while (remainder >= 11UL)
|
||||||
|
{
|
||||||
|
remainder -= 11UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod128(this UInt128 value) => (ulong)value & 127UL;
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static UInt128 Mul64(this UInt128 a, UInt128 b)
|
public static UInt128 Mul64(this UInt128 a, UInt128 b)
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
|
public static class UIntExtensions
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod3(this uint value) => PerfectNumbersMath.FastRemainder3(value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod5(this uint value) => PerfectNumbersMath.FastRemainder5(value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod7(this uint value)
|
||||||
|
{
|
||||||
|
uint remainder = 0U;
|
||||||
|
uint temp = value;
|
||||||
|
|
||||||
|
while (temp != 0U)
|
||||||
|
{
|
||||||
|
remainder += temp & 7U;
|
||||||
|
temp >>= 3;
|
||||||
|
if (remainder >= 7U)
|
||||||
|
{
|
||||||
|
remainder -= 7U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainder >= 7U ? remainder - 7U : remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod8(this uint value) => value & 7U;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod10(this uint value)
|
||||||
|
{
|
||||||
|
uint quotient = (uint)(((ulong)value * 0xCCCCCCCDUL) >> 35);
|
||||||
|
return value - quotient * 10U;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod11(this uint value)
|
||||||
|
{
|
||||||
|
uint remainder = 0U;
|
||||||
|
uint temp = value;
|
||||||
|
|
||||||
|
while (temp != 0U)
|
||||||
|
{
|
||||||
|
remainder += temp & 1023U;
|
||||||
|
temp >>= 10;
|
||||||
|
remainder -= 11U * (remainder / 11U);
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint Mod128(this uint value) => value & 127U;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -98,6 +98,17 @@ public static class ULongExtensions
|
|||||||
mod3 = mod3Value;
|
mod3 = mod3Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[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)
|
||||||
|
{
|
||||||
|
value.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
||||||
|
|
||||||
|
step10 = (mod10 << 1).Mod10();
|
||||||
|
step8 = ((mod8 << 1) & 7UL);
|
||||||
|
step5 = (mod5 << 1).Mod5();
|
||||||
|
step3 = (mod3 << 1).Mod3();
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsPrimeCandidate(this ulong n)
|
public static bool IsPrimeCandidate(this ulong n)
|
||||||
{
|
{
|
||||||
@@ -130,6 +141,64 @@ public static class ULongExtensions
|
|||||||
return value - quotient * 10UL;
|
return value - quotient * 10UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod8(this ulong value) => value & 7UL;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod3(this ulong value)
|
||||||
|
{
|
||||||
|
uint sum = (uint)(value & 0xFFFFUL);
|
||||||
|
sum += (uint)((value >> 16) & 0xFFFFUL);
|
||||||
|
sum += (uint)((value >> 32) & 0xFFFFUL);
|
||||||
|
sum += (uint)((value >> 48) & 0xFFFFUL);
|
||||||
|
|
||||||
|
return PerfectNumbersMath.FastRemainder3(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod5(this ulong value)
|
||||||
|
{
|
||||||
|
uint sum = (uint)(value & 0xFFFFUL);
|
||||||
|
sum += (uint)((value >> 16) & 0xFFFFUL);
|
||||||
|
sum += (uint)((value >> 32) & 0xFFFFUL);
|
||||||
|
sum += (uint)((value >> 48) & 0xFFFFUL);
|
||||||
|
|
||||||
|
return PerfectNumbersMath.FastRemainder5(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod7(this ulong value)
|
||||||
|
{
|
||||||
|
uint low = (uint)value;
|
||||||
|
uint high = (uint)(value >> 32);
|
||||||
|
|
||||||
|
ulong remainder = low.Mod7() + (ulong)high.Mod7() * 4UL;
|
||||||
|
while (remainder >= 7UL)
|
||||||
|
{
|
||||||
|
remainder -= 7UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod11(this ulong value)
|
||||||
|
{
|
||||||
|
uint low = (uint)value;
|
||||||
|
uint high = (uint)(value >> 32);
|
||||||
|
|
||||||
|
ulong remainder = low.Mod11() + (ulong)high.Mod11() * 4UL;
|
||||||
|
while (remainder >= 11UL)
|
||||||
|
{
|
||||||
|
remainder -= 11UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ulong Mod128(this ulong value) => value & 127UL;
|
||||||
|
|
||||||
[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