Add optimized modulo helpers for unsigned integers
This commit is contained in:
1 parent
2c2bc62cb2
commit
95a0b030f6
7 files changed
+425
-84
No files matched your search
@@ -24,10 +24,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
||||
UInt128 kStart = 1UL;
|
||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||
var kernel = gpuLease.Pow2ModKernel;
|
||||
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||
exponent.Mod10_8_5_3Steps(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
|
||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||
|
||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||
|
||||
@@ -203,48 +203,73 @@ public static class UInt128Extensions
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod10(this UInt128 value)
|
||||
{
|
||||
UInt128 zero = UInt128.Zero;
|
||||
if (value == zero)
|
||||
return 0UL;
|
||||
public static ulong Mod10(this UInt128 value)
|
||||
{
|
||||
UInt128 zero = UInt128.Zero;
|
||||
if (value == zero)
|
||||
return 0UL;
|
||||
|
||||
ulong result = (ulong)value;
|
||||
UInt128 high = value >> 64;
|
||||
ulong result = (ulong)value;
|
||||
UInt128 high = value >> 64;
|
||||
|
||||
while (high != zero)
|
||||
{
|
||||
// 2^64 ≡ 6 (mod 10)
|
||||
result = (result + (ulong)high * 6UL).Mod10();
|
||||
high >>= 64;
|
||||
}
|
||||
while (high != zero)
|
||||
{
|
||||
// 2^64 ≡ 6 (mod 10)
|
||||
result = (result + (ulong)high * 6UL).Mod10();
|
||||
high >>= 64;
|
||||
}
|
||||
|
||||
return result.Mod10();
|
||||
}
|
||||
return result.Mod10();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod8(this UInt128 value) => (ulong)value & 7UL;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod3(this UInt128 value)
|
||||
{
|
||||
// 2^64 ≡ 1 (mod 3)
|
||||
ulong rem = ((ulong)value % 3UL) + ((ulong)(value >> 64) % 3UL);
|
||||
return rem >= 3UL ? rem - 3UL : rem;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod8(this UInt128 value) => (ulong)value & 7UL;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod5(this UInt128 value)
|
||||
{
|
||||
// 2^64 ≡ 1 (mod 5)
|
||||
ulong rem = ((ulong)value % 5UL) + ((ulong)(value >> 64) % 5UL);
|
||||
return rem >= 5UL ? rem - 5UL : rem;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod3(this UInt128 value)
|
||||
{
|
||||
ulong remainder = ((ulong)value).Mod3() + ((ulong)(value >> 64)).Mod3();
|
||||
return remainder >= 3UL ? remainder - 3UL : remainder;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod5(this UInt128 value)
|
||||
{
|
||||
ulong remainder = ((ulong)value).Mod5() + ((ulong)(value >> 64)).Mod5();
|
||||
return remainder >= 5UL ? remainder - 5UL : remainder;
|
||||
}
|
||||
|
||||
[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)]
|
||||
public static UInt128 Mul64(this UInt128 a, UInt128 b)
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static UInt128 Mul64(this UInt128 a, UInt128 b)
|
||||
{
|
||||
ulong aLow = (ulong)a;
|
||||
ulong bLow = (ulong)b;
|
||||
return ((UInt128)(aLow * (ulong)(b >> 64) + aLow.MulHigh(bLow)) << 64) | (aLow * bLow);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -58,51 +58,62 @@ public static class ULongExtensions
|
||||
}
|
||||
|
||||
[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;
|
||||
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);
|
||||
do
|
||||
{
|
||||
byteSum += (byte)temp;
|
||||
temp >>= 8;
|
||||
}
|
||||
while (temp != 0UL);
|
||||
|
||||
mod8 = value & 7UL;
|
||||
mod8 = value & 7UL;
|
||||
|
||||
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
||||
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
||||
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,
|
||||
};
|
||||
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;
|
||||
}
|
||||
mod5 = mod5Value;
|
||||
mod3 = mod3Value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsPrimeCandidate(this ulong n)
|
||||
{
|
||||
int i = 0;
|
||||
ulong p;
|
||||
[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)]
|
||||
public static bool IsPrimeCandidate(this ulong n)
|
||||
{
|
||||
int i = 0;
|
||||
ulong p;
|
||||
uint[] smallPrimes = PrimesGenerator.SmallPrimes;
|
||||
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
|
||||
int len = smallPrimes.Length;
|
||||
@@ -123,12 +134,70 @@ public static class ULongExtensions
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod10(this ulong value)
|
||||
{
|
||||
ulong quotient = (ulong)(((UInt128)value * 0xCCCCCCCCCCCCCCCDUL) >> 67);
|
||||
return value - quotient * 10UL;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod10(this ulong value)
|
||||
{
|
||||
ulong quotient = (ulong)(((UInt128)value * 0xCCCCCCCCCCCCCCCDUL) >> 67);
|
||||
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)]
|
||||
public static UInt128 Mul64(this ulong a, ulong b) => ((UInt128)a.MulHigh(b) << 64) | (UInt128)(a * b);
|
||||
|
||||
Reference in new issue
Block a user