diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index 835b80d..fa20429 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -720,6 +720,63 @@ internal static partial class PrimeOrderCalculator return isPrime; } + + [ThreadStatic] + private static Dictionary? _partialFactorPrimalityCache; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ResetPartialFactorPrimalityCache() + { + Dictionary? cache = _partialFactorPrimalityCache; + if (cache is not null && cache.Count > 0) + { + cache.Clear(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Dictionary GetPartialFactorPrimalityCache() + { + Dictionary? cache = _partialFactorPrimalityCache; + if (cache is null) + { + cache = ThreadStaticPools.RentUlongBoolDictionary(4); + _partialFactorPrimalityCache = cache; + } + + return cache; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool EvaluatePrimalityPartialFactor(ulong candidate) + { + if (TryGetCachedPrimality(candidate, out bool cached)) + { + return cached; + } + + ulong globalCacheLimit = (ulong)PerfectNumberConstants.MaxQForDivisorCycles; + if (candidate > globalCacheLimit) + { + Dictionary? cache = _partialFactorPrimalityCache; + if (cache is not null && cache.TryGetValue(candidate, out bool cachedValue)) + { + return cachedValue; + } + } + + bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(candidate); + CachePrimalityResult(candidate, isPrime); + + if (candidate > globalCacheLimit) + { + Dictionary cache = GetPartialFactorPrimalityCache(); + cache[candidate] = isPrime; + } + + return isPrime; + } + private static PartialFactorResult PartialFactor(ulong value, in PrimeOrderSearchConfig config) { if (value <= 1UL) @@ -757,26 +814,7 @@ internal static partial class PrimeOrderCalculator Stack? compositeStack = null; PartialFactorResult result; - Dictionary? localPrimalityCache = null; - - bool EvaluatePrimality(ulong candidate) - { - Dictionary? cache = localPrimalityCache; - if (cache is not null && cache.TryGetValue(candidate, out bool cachedValue)) - { - return cachedValue; - } - - bool computed = GetOrComputePrimality(candidate); - if (!computed) - { - cache ??= ThreadStaticPools.RentUlongBoolDictionary(4); - cache[candidate] = false; - localPrimalityCache = cache; - } - - return computed; - } + ResetPartialFactorPrimalityCache(); if (!gpuFactored) { @@ -842,7 +880,7 @@ internal static partial class PrimeOrderCalculator // continue; // } - bool isPrime = EvaluatePrimality(composite); + bool isPrime = EvaluatePrimalityPartialFactor(composite); if (isPrime) { @@ -889,7 +927,7 @@ internal static partial class PrimeOrderCalculator continue; } - bool isPrime = EvaluatePrimality(composite); + bool isPrime = EvaluatePrimalityPartialFactor(composite); if (isPrime) { @@ -915,7 +953,7 @@ internal static partial class PrimeOrderCalculator } else { - cofactorIsPrime = EvaluatePrimality(cofactor); + cofactorIsPrime = EvaluatePrimalityPartialFactor(cofactor); } ArrayPool pool = ThreadStaticPools.FactorEntryPool; @@ -989,10 +1027,6 @@ internal static partial class PrimeOrderCalculator // ThreadStaticPools.UlongPool.Return(primeSlotsArray); // ThreadStaticPools.IntPool.Return(exponentSlotsArray); - if (localPrimalityCache is not null) - { - ThreadStaticPools.ReturnUlongBoolDictionary(localPrimalityCache); - } if (counts is not null) {