From e525484b4879fb7a4345fe4310262e99d8ec1201 Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Fri, 17 Oct 2025 16:24:59 +0200 Subject: [PATCH] Primality tests normalized on GetOrComputePrimality. CofactorIsPrime added to factoring results for reuse in other places. --- PerfectNumbers.Core/FactorEntry.cs | 5 +- PerfectNumbers.Core/PartialFactorResult.cs | 22 ++++---- .../PrimeOrderCalculator.Cpu.cs | 50 +++++++++---------- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/PerfectNumbers.Core/FactorEntry.cs b/PerfectNumbers.Core/FactorEntry.cs index e4ba3be..56fff8e 100644 --- a/PerfectNumbers.Core/FactorEntry.cs +++ b/PerfectNumbers.Core/FactorEntry.cs @@ -1,8 +1,9 @@ namespace PerfectNumbers.Core { - public readonly struct FactorEntry(ulong value, int exponent) + public readonly struct FactorEntry(ulong value, int exponent, bool isPrime) { public readonly ulong Value = value; - public readonly int Exponent = exponent; + public readonly int Exponent = exponent; + public readonly bool CofactorIsPrime = isPrime; } } \ No newline at end of file diff --git a/PerfectNumbers.Core/PartialFactorResult.cs b/PerfectNumbers.Core/PartialFactorResult.cs index c7e4a60..bf45ad4 100644 --- a/PerfectNumbers.Core/PartialFactorResult.cs +++ b/PerfectNumbers.Core/PartialFactorResult.cs @@ -11,13 +11,14 @@ namespace PerfectNumbers.Core private PartialFactorResult? _next; public ulong Cofactor; public bool FullyFactored; - public int Count; + public int Count; + public bool CofactorIsPrime; private PartialFactorResult() { } - public static PartialFactorResult Rent(in FactorEntry[]? factors, ulong cofactor, bool fullyFactored, int count) + public static PartialFactorResult Rent(in FactorEntry[]? factors, ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime) { PartialFactorResult? instance = s_poolHead; if (instance is null) @@ -33,15 +34,16 @@ namespace PerfectNumbers.Core instance.Factors = factors; instance.Cofactor = cofactor; instance.FullyFactored = fullyFactored; - instance.Count = count; + instance.Count = count; + instance.CofactorIsPrime = cofactorIsPrime; return instance; } public static readonly PartialFactorResult Empty = new() { - Cofactor = 1UL, - FullyFactored = true, - }; + Cofactor = 1UL, + FullyFactored = true + }; public PartialFactorResult WithAdditionalPrime(ulong prime) { @@ -49,16 +51,16 @@ namespace PerfectNumbers.Core if (source is null || Count == 0) { FactorEntry[] local = ArrayPool.Shared.Rent(1); - local[0] = new FactorEntry(prime, 1); - return Rent(local, 1UL, true, 1); + local[0] = new FactorEntry(prime, 1, true); + return Rent(local, 1UL, true, 1, false); } FactorEntry[] extended = ArrayPool.Shared.Rent(Count + 1); Array.Copy(source, 0, extended, 0, Count); - extended[Count] = new FactorEntry(prime, 1); + extended[Count] = new FactorEntry(prime, 1, true); Span span = extended.AsSpan(0, Count + 1); span.Sort(static (a, b) => a.Value.CompareTo(b.Value)); - return Rent(extended, 1UL, true, Count + 1); + return Rent(extended, 1UL, true, Count + 1, false); } public void Dispose() diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index 9cf94df..bae7f92 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -126,11 +126,11 @@ internal static partial class PrimeOrderCalculator Span buffer = tempArray; factorSpan.CopyTo(buffer); - bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factors.Cofactor); // bool isPrime = PrimeTester.IsPrimeInternal(factors.Cofactor, CancellationToken.None); - if (!factors.FullyFactored && factors.Cofactor > 1UL && isPrime) + // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factors.Cofactor); + if (!factors.FullyFactored && factors.Cofactor > 1UL && factors.CofactorIsPrime) { - buffer[length] = new FactorEntry(factors.Cofactor, 1); + buffer[length] = new FactorEntry(factors.Cofactor, 1, true); length++; } @@ -190,14 +190,7 @@ internal static partial class PrimeOrderCalculator if (!factorization.FullyFactored) { - if (factorization.Cofactor <= 1UL) - { - factorization.Dispose(); - return false; - } - - bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factorization.Cofactor); - if (!isPrime) + if (factorization.Cofactor <= 1UL || !factorization.CofactorIsPrime) { factorization.Dispose(); return false; @@ -281,9 +274,8 @@ internal static partial class PrimeOrderCalculator return false; } - var isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(orderFactors.Cofactor); // if (!PrimeTester.IsPrimeInternal(orderFactors.Cofactor, CancellationToken.None)) - if (!isPrime) + if (!orderFactors.CofactorIsPrime) { return false; } @@ -607,9 +599,9 @@ internal static partial class PrimeOrderCalculator return false; } - bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factorization.Cofactor); + // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factorization.Cofactor); // bool isPrime = PrimeTester.IsPrimeInternal(factorization.Cofactor, CancellationToken.None); - if (!isPrime) + if (!factorization.CofactorIsPrime) { return false; } @@ -839,9 +831,10 @@ internal static partial class PrimeOrderCalculator ulong cofactor = 1UL; int pendingCount = pending.Count; - for (int i = 0; i < pendingCount; i++) + int index = 0; + for (; index < pendingCount; index++) { - ulong composite = pending[i]; + ulong composite = pending[index]; bool isPrime = GetOrComputePrimality(composite); if (isPrime) @@ -856,33 +849,35 @@ internal static partial class PrimeOrderCalculator } } + bool cofactorIsPrime = GetOrComputePrimality(cofactor); ArrayPool pool = ThreadStaticPools.FactorEntryPool; + bool temp; if (useDictionary) { if ((counts is null || counts.Count == 0) && cofactor == value) { - result = PartialFactorResult.Rent(null, value, false, 0); + result = PartialFactorResult.Rent(null, cofactor, false, 0, cofactorIsPrime); goto ReturnResult; } if (counts is null || counts.Count == 0) { - result = PartialFactorResult.Rent(null, cofactor, cofactor == 1UL, 0); + result = PartialFactorResult.Rent(null, cofactor, cofactor == 1UL, 0, cofactorIsPrime); goto ReturnResult; } FactorEntry[] factors = pool.Rent(counts.Count); - int index = 0; + index = 0; foreach (KeyValuePair entry in counts) { - factors[index] = new FactorEntry(entry.Key, entry.Value); + factors[index] = new FactorEntry(entry.Key, entry.Value, true); index++; } Array.Sort(factors, static (a, b) => a.Value.CompareTo(b.Value)); - bool fullyFactored = cofactor == 1UL; - result = PartialFactorResult.Rent(factors, cofactor, fullyFactored, index); + temp = cofactor == 1UL; + result = PartialFactorResult.Rent(factors, cofactor, temp, index, cofactorIsPrime); goto ReturnResult; } @@ -912,14 +907,14 @@ internal static partial class PrimeOrderCalculator // continue; // } - array[arrayIndex] = new FactorEntry(primeValue, exponentValue); + array[arrayIndex] = new FactorEntry(primeValue, exponentValue, true); arrayIndex++; } Span arraySpan = array.AsSpan(0, arrayIndex); arraySpan.Sort(static (a, b) => a.Value.CompareTo(b.Value)); - bool fullyFactoredArray = cofactor == 1UL; - result = PartialFactorResult.Rent(array, cofactor, fullyFactoredArray, arrayIndex); + temp = cofactor == 1UL; + result = PartialFactorResult.Rent(array, cofactor, temp, arrayIndex, cofactorIsPrime); ReturnResult: // ThreadStaticPools.UlongPool.Return(primeSlotsArray); @@ -1372,7 +1367,8 @@ internal static partial class PrimeOrderCalculator return; } - if (Open.Numeric.Primes.Prime.Numbers.IsPrime(value)) + // if (Open.Numeric.Primes.Prime.Numbers.IsPrime(value)) + if (GetOrComputePrimality(value)) { AddFactor(counts, value, 1); return;