Reapply modulo helpers and inline fast remainders
This commit is contained in:
1 parent
5db0c4fa95
commit
ca866ffc5b
43 files changed
+982
-134
No files matched your search
@@ -8,12 +8,16 @@ public class MersenneNumberLucasLehmerCpuTester
|
||||
// - 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 is divisible by divisors specific to numbers ending with 1 or 7, reject fast.
|
||||
if (
|
||||
((exponent % 3UL) == 0UL && exponent != 3UL) ||
|
||||
((exponent % 5UL) == 0UL && exponent != 5UL) ||
|
||||
((exponent % 7UL) == 0UL && exponent != 7UL) ||
|
||||
((exponent % 11UL) == 0UL && exponent != 11UL)
|
||||
)
|
||||
ulong mod3 = exponent.Mod3();
|
||||
ulong mod5 = exponent.Mod5();
|
||||
ulong mod7 = exponent.Mod7();
|
||||
ulong mod11 = exponent.Mod11();
|
||||
if (
|
||||
(mod3 == 0UL && exponent != 3UL) ||
|
||||
(mod5 == 0UL && exponent != 5UL) ||
|
||||
(mod7 == 0UL && exponent != 7UL) ||
|
||||
(mod11 == 0UL && exponent != 11UL)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public class MersenneNumberResidueCpuTester
|
||||
q.Mod10_8_5_3(out ulong r10, out ulong r8, out ulong r5, out ulong r3);
|
||||
// Step residues for q += 2*p
|
||||
twoP.Mod10_8_5_3(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
|
||||
step10 = step10.Mod10();
|
||||
step10 %= 10UL;
|
||||
|
||||
// Allowed last-digit sets for q depending on last digit of M_p
|
||||
// lastIsSeven == true => allow {7,9}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
||||
// Early rejections aligned with incremental/order sieves, but safe for small p:
|
||||
// - 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 ((exponent % 3UL) == 0UL && exponent != 3UL)
|
||||
if (exponent % 3UL == 0UL && exponent != 3UL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -548,7 +548,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
||||
}
|
||||
}
|
||||
|
||||
int topBits = (int)(exponent % 128UL);
|
||||
int topBits = (int)exponent.Mod128();
|
||||
if (topBits == 0)
|
||||
{
|
||||
topBits = 128;
|
||||
@@ -672,7 +672,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
||||
}
|
||||
}
|
||||
|
||||
int topBits = (int)(exponent % 128UL);
|
||||
int topBits = (int)exponent.Mod128();
|
||||
if (topBits == 0)
|
||||
{
|
||||
topBits = 128;
|
||||
@@ -803,7 +803,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
||||
vLow.Add(vHigh);
|
||||
|
||||
// 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)
|
||||
{
|
||||
topBits = 128;
|
||||
|
||||
@@ -27,10 +27,10 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
||||
var foundBuffer = accelerator.Allocate1D<int>(1);
|
||||
UInt128 exponent128 = exponent;
|
||||
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) % 10UL;
|
||||
ulong step8 = (exponentMod8 << 1) & 7UL;
|
||||
ulong step3 = (exponentMod3 << 1) % 3UL;
|
||||
ulong step5 = (exponentMod5 << 1) % 5UL;
|
||||
ulong step3 = (exponentMod3 << 1) % 3UL;
|
||||
ulong step5 = (exponentMod5 << 1) % 5UL;
|
||||
try
|
||||
{
|
||||
UInt128 remaining;
|
||||
|
||||
@@ -67,7 +67,7 @@ public sealed class MersenneNumberTester(
|
||||
for (; k <= limit; k++)
|
||||
{
|
||||
q = twoP * k + UInt128.One;
|
||||
remainder = q.Mod10();
|
||||
remainder = (ulong)(q % 10UL);
|
||||
bool shouldCheck = lastIsSeven
|
||||
? remainder == 7UL || remainder == 9UL || remainder == 3UL
|
||||
: remainder == 1UL || remainder == 3UL || remainder == 9UL;
|
||||
@@ -75,12 +75,12 @@ public sealed class MersenneNumberTester(
|
||||
// Early modular filters for odd order and small-prime rejections
|
||||
if (shouldCheck)
|
||||
{
|
||||
ulong mod8 = q.Mod8();
|
||||
ulong mod8 = (ulong)(q % 8UL);
|
||||
if (mod8 != 1UL && mod8 != 7UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (q.Mod3() == 0UL || q.Mod5() == 0UL)
|
||||
else if ((ulong)(q % 3UL) == 0UL || (ulong)(q % 5UL) == 0UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ public sealed class MersenneNumberTester(
|
||||
for (; k2 <= limit; k2++)
|
||||
{
|
||||
q2 = twoP * k2 + 1UL;
|
||||
remainder2 = q2.Mod10();
|
||||
remainder2 = (ulong)(q2 % 10UL);
|
||||
bool shouldCheck2 = lastIsSeven
|
||||
? remainder2 == 7UL || remainder2 == 9UL || remainder2 == 3UL
|
||||
: remainder2 == 1UL || remainder2 == 3UL || remainder2 == 9UL;
|
||||
@@ -114,12 +114,12 @@ public sealed class MersenneNumberTester(
|
||||
// Early modular filters for odd order and small-prime rejections
|
||||
if (shouldCheck2)
|
||||
{
|
||||
ulong mod8 = q2.Mod8();
|
||||
ulong mod8 = (ulong)(q2 % 8UL);
|
||||
if (mod8 != 1UL && mod8 != 7UL)
|
||||
{
|
||||
shouldCheck2 = false;
|
||||
}
|
||||
else if (q2.Mod3() == 0UL || q2.Mod5() == 0UL)
|
||||
else if ((ulong)(q2 % 3UL) == 0UL || (ulong)(q2 % 5UL) == 0UL)
|
||||
{
|
||||
shouldCheck2 = false;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ public sealed class MersenneNumberTester(
|
||||
{
|
||||
// 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.
|
||||
if ((exponent % 3UL) == 0UL && exponent != 3UL)
|
||||
if (exponent % 3UL == 0UL && exponent != 3UL)
|
||||
{
|
||||
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,13 +53,13 @@ public sealed class PrimeTester(bool useInternal = false)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else if (n > 5UL && (n % 5UL) == 0UL)
|
||||
else if (n > 5UL && n % 5UL == 0UL)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n.Mod10() == 1UL && SharesFactorWithMaxExponent(n))
|
||||
if (n % 10UL == 1UL && SharesFactorWithMaxExponent(n))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
@@ -260,13 +260,13 @@ public sealed class PrimeTester(bool useInternal = false)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((n & 1UL) == 0UL || (n > 5UL && (n % 5UL) == 0UL))
|
||||
if ((n & 1UL) == 0UL || (n > 5UL && n % 5UL == 0UL))
|
||||
{
|
||||
results[index] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (n.Mod10() == 1UL)
|
||||
if (n % 10UL == 1UL)
|
||||
{
|
||||
// Early reject special GCD heuristic with floor(log2 n)
|
||||
ulong m = 63UL - (ulong)ILGPU.Algorithms.XMath.LeadingZeroCount(n);
|
||||
|
||||
@@ -100,14 +100,14 @@ public static class PrimesGenerator
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool IsAllowedForLastOne(uint prime)
|
||||
{
|
||||
uint mod10 = prime % 10U;
|
||||
uint mod10 = prime % 10U;
|
||||
return mod10 == 1U || mod10 == 3U || mod10 == 9U || prime == 7U || prime == 11U;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool IsAllowedForLastSeven(uint prime)
|
||||
{
|
||||
uint mod10 = prime % 10U;
|
||||
uint mod10 = prime % 10U;
|
||||
return mod10 == 3U || mod10 == 7U || mod10 == 9U || prime == 11U;
|
||||
}
|
||||
}
|
||||
@@ -135,8 +135,8 @@ public static class UInt128Extensions
|
||||
|
||||
mod8 = (ulong)value & 7UL;
|
||||
|
||||
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
||||
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
||||
uint mod5Value = byteSum.Mod5();
|
||||
uint mod3Value = byteSum.Mod3();
|
||||
|
||||
mod10 = (mod8 & 1UL) == 0UL
|
||||
? mod5Value switch
|
||||
@@ -238,6 +238,22 @@ public static class UInt128Extensions
|
||||
return remainder >= 5UL ? remainder - 5UL : remainder;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod6(this UInt128 value)
|
||||
{
|
||||
ulong mod3 = value.Mod3();
|
||||
ulong key = (mod3 << 1) | ((ulong)value & 1UL);
|
||||
return key switch
|
||||
{
|
||||
0UL => 0UL,
|
||||
1UL => 3UL,
|
||||
2UL => 4UL,
|
||||
3UL => 1UL,
|
||||
4UL => 2UL,
|
||||
_ => 5UL,
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod7(this UInt128 value)
|
||||
{
|
||||
|
||||
@@ -4,57 +4,74 @@ namespace PerfectNumbers.Core;
|
||||
|
||||
public static class UIntExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod3(this uint value) => PerfectNumbersMath.FastRemainder3(value);
|
||||
private static readonly byte[] Mod6Lookup = { 0, 3, 4, 1, 2, 5 };
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod5(this uint value) => PerfectNumbersMath.FastRemainder5(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod3(this uint value)
|
||||
{
|
||||
uint quotient = (uint)(((ulong)value * 0xAAAAAAABUL) >> 33);
|
||||
return value - quotient * 3U;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod7(this uint value)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod5(this uint value)
|
||||
{
|
||||
uint quotient = (uint)(((ulong)value * 0xCCCCCCCDUL) >> 34);
|
||||
return value - quotient * 5U;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod6(this uint value)
|
||||
{
|
||||
uint key = (value.Mod3() << 1) | (value & 1U);
|
||||
return Mod6Lookup[(int)key];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod7(this uint value)
|
||||
{
|
||||
uint remainder = 0U;
|
||||
uint temp = value;
|
||||
|
||||
while (temp != 0U)
|
||||
{
|
||||
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;
|
||||
remainder += temp & 7U;
|
||||
temp >>= 3;
|
||||
if (remainder >= 7U)
|
||||
{
|
||||
remainder -= 7U;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod8(this uint value) => value & 7U;
|
||||
return remainder >= 7U ? remainder - 7U : remainder;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod10(this uint value)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod8(this uint value) => value & 7U;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod10(this uint value)
|
||||
{
|
||||
return value - (uint)(((ulong)value * 0xCCCCCCCDUL) >> 35) * 10U;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod11(this uint value)
|
||||
{
|
||||
uint remainder = 0U;
|
||||
uint temp = value;
|
||||
|
||||
while (temp != 0U)
|
||||
{
|
||||
return value - (uint)(((ulong)value * 0xCCCCCCCDUL) >> 35) * 10U;
|
||||
remainder += temp & 1023U;
|
||||
temp >>= 10;
|
||||
remainder -= 11U * (remainder / 11U);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod11(this uint value)
|
||||
{
|
||||
uint remainder = 0U;
|
||||
uint temp = value;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
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;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod128(this uint value) => value & 127U;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,11 @@ public static class ULongExtensions
|
||||
return q;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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)]
|
||||
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;
|
||||
@@ -72,8 +76,8 @@ public static class ULongExtensions
|
||||
|
||||
mod8 = value & 7UL;
|
||||
|
||||
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
||||
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
||||
uint mod5Value = byteSum.Mod5();
|
||||
uint mod3Value = byteSum.Mod3();
|
||||
|
||||
mod10 = (mod8 & 1UL) == 0UL
|
||||
? mod5Value switch
|
||||
@@ -97,6 +101,35 @@ public static class ULongExtensions
|
||||
mod3 = mod3Value;
|
||||
}
|
||||
|
||||
[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 = value;
|
||||
int index = 0;
|
||||
|
||||
do
|
||||
{
|
||||
byte current = (byte)temp;
|
||||
mod3Accumulator += current;
|
||||
mod5Accumulator += current;
|
||||
mod7Accumulator += (uint)(current * Mod7ByteCoefficients[index]);
|
||||
mod11Accumulator += (uint)(current * Mod11ByteCoefficients[index]);
|
||||
|
||||
temp >>= 8;
|
||||
index++;
|
||||
}
|
||||
while (temp != 0UL);
|
||||
|
||||
mod3 = mod3Accumulator.Mod3();
|
||||
mod5 = mod5Accumulator.Mod5();
|
||||
mod7 = ReduceMod7(mod7Accumulator);
|
||||
mod11 = ReduceMod11(mod11Accumulator);
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
@@ -171,7 +204,7 @@ public static class ULongExtensions
|
||||
sum += (uint)((value >> 32) & 0xFFFFUL);
|
||||
sum += (uint)((value >> 48) & 0xFFFFUL);
|
||||
|
||||
return PerfectNumbersMath.FastRemainder3(sum);
|
||||
return sum.Mod3();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -182,7 +215,14 @@ public static class ULongExtensions
|
||||
sum += (uint)((value >> 32) & 0xFFFFUL);
|
||||
sum += (uint)((value >> 48) & 0xFFFFUL);
|
||||
|
||||
return PerfectNumbersMath.FastRemainder5(sum);
|
||||
return sum.Mod5();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod6(this ulong value)
|
||||
{
|
||||
ulong key = (value.Mod3() << 1) | (value & 1UL);
|
||||
return Mod6Lookup[(int)key];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -218,6 +258,36 @@ public static class ULongExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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)]
|
||||
public static UInt128 Mul64(this ulong a, ulong b) => ((UInt128)a.MulHigh(b) << 64) | (UInt128)(a * b);
|
||||
|
||||
|
||||
Reference in new issue
Block a user