46 lines
1.3 KiB
C#
46 lines
1.3 KiB
C#
namespace PerfectNumbers.Core;
|
|
|
|
public class MersenneNumberLucasLehmerCpuTester
|
|
{
|
|
public bool IsPrime(ulong exponent)
|
|
{
|
|
// 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 p is divisible by divisors specific to numbers ending with 1 or 7, reject fast.
|
|
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;
|
|
}
|
|
|
|
if ((exponent & 3UL) == 1UL && exponent.SharesFactorWithExponentMinusOne())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UInt128 s = UInt128Numbers.Four, two = UInt128Numbers.Two,
|
|
m = (UInt128.One << (int)exponent) - UInt128.One;
|
|
|
|
UInt128 limit = exponent - UInt128Numbers.Two;
|
|
for (UInt128 i = UInt128.Zero; i < limit; i++)
|
|
{
|
|
s = s.PowModWithCycle(two, MersenneDivisorCycles.GetCycle(m)) - two;
|
|
if (s < UInt128.Zero)
|
|
{
|
|
s += m;
|
|
}
|
|
}
|
|
|
|
return s == UInt128.Zero;
|
|
}
|
|
}
|