Streamline by-divisor cycle equality checks

This commit is contained in:
Marek Lemańczyk committed 2025-10-05 21:32:40 +02:00
1 parent ac846df7d9
commit 16181903a1
3 files changed
+149 -275

No files matched your search

@@ -54,6 +54,100 @@ public class MersenneDivisorCycles
return snapshot;
}
public static bool CycleEqualsExponent(ulong divisor, ulong exponent)
{
Dictionary<ulong, FactorCacheEntry>? cache = null;
return CycleEqualsExponent(divisor, exponent, ref cache);
}
public static bool CycleEqualsExponent(ulong divisor, ulong exponent, ref Dictionary<ulong, FactorCacheEntry>? factorCache)
{
if (CycleEqualsExponentForMersenneCandidate(divisor, exponent))
{
return true;
}
if (exponent <= 1UL || divisor <= 1UL || (divisor & 1UL) == 0UL)
{
return false;
}
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
{
var small = Shared._smallCycles;
if (small is not null)
{
ulong cached = small[(int)divisor];
if (cached != 0UL)
{
return cached == exponent;
}
}
}
if (TryCalculateCycleLengthHeuristic(divisor, out ulong heuristicCycle) && heuristicCycle != 0UL)
{
return heuristicCycle == exponent;
}
Dictionary<ulong, FactorCacheEntry>? cache = factorCache;
if (cache is null)
{
cache = new Dictionary<ulong, FactorCacheEntry>(8);
factorCache = cache;
}
if (TryCalculateCycleLengthForExponent(divisor, exponent, cache, out ulong cycleLength) && cycleLength != 0UL)
{
return cycleLength == exponent;
}
MontgomeryDivisorData divisorData = MontgomeryDivisorDataCache.Get(divisor);
return exponent.Pow2MontgomeryModWindowed(divisorData, keepMontgomery: false) == 1UL;
}
public static bool CycleEqualsExponentForMersenneCandidate(ulong divisor, ulong exponent)
{
if (!IsValidMersenneDivisorCandidate(divisor, exponent))
{
return false;
}
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
{
MersenneDivisorCycles shared = Shared;
ulong[]? small = shared._smallCycles;
if (small is not null)
{
ulong cached = small[(int)divisor];
if (cached != 0UL)
{
return cached == exponent;
}
}
}
MontgomeryDivisorData divisorData = MontgomeryDivisorDataCache.Get(divisor);
return exponent.Pow2MontgomeryModWindowed(divisorData, keepMontgomery: false) == 1UL;
}
private static bool IsValidMersenneDivisorCandidate(ulong divisor, ulong exponent)
{
if (exponent <= 1UL || divisor <= 1UL || (divisor & 1UL) == 0UL)
{
return false;
}
UInt128 step = (UInt128)exponent << 1;
if (step == UInt128.Zero)
{
return false;
}
UInt128 adjusted = (UInt128)divisor - UInt128.One;
return adjusted % step == UInt128.Zero;
}
public static IEnumerable<(ulong divisor, ulong cycleLength)> EnumerateStream(Stream compressor)
{
// Binary pairs: (ulong divisor, ulong cycle)