Primality tests normalized on GetOrComputePrimality. CofactorIsPrime added to factoring results for reuse in other places.

This commit is contained in:
mlemanczyk committed 2025-10-17 16:24:59 +02:00
1 parent c0f38fa104
commit e525484b48
3 files changed
+38 -39

No files matched your search

+3 -2
View File
@@ -1,8 +1,9 @@
namespace PerfectNumbers.Core 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 ulong Value = value;
public readonly int Exponent = exponent; public readonly int Exponent = exponent;
public readonly bool CofactorIsPrime = isPrime;
} }
} }
+12 -10
View File
@@ -11,13 +11,14 @@ namespace PerfectNumbers.Core
private PartialFactorResult? _next; private PartialFactorResult? _next;
public ulong Cofactor; public ulong Cofactor;
public bool FullyFactored; public bool FullyFactored;
public int Count; public int Count;
public bool CofactorIsPrime;
private PartialFactorResult() 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; PartialFactorResult? instance = s_poolHead;
if (instance is null) if (instance is null)
@@ -33,15 +34,16 @@ namespace PerfectNumbers.Core
instance.Factors = factors; instance.Factors = factors;
instance.Cofactor = cofactor; instance.Cofactor = cofactor;
instance.FullyFactored = fullyFactored; instance.FullyFactored = fullyFactored;
instance.Count = count; instance.Count = count;
instance.CofactorIsPrime = cofactorIsPrime;
return instance; return instance;
} }
public static readonly PartialFactorResult Empty = new() public static readonly PartialFactorResult Empty = new()
{ {
Cofactor = 1UL, Cofactor = 1UL,
FullyFactored = true, FullyFactored = true
}; };
public PartialFactorResult WithAdditionalPrime(ulong prime) public PartialFactorResult WithAdditionalPrime(ulong prime)
{ {
@@ -49,16 +51,16 @@ namespace PerfectNumbers.Core
if (source is null || Count == 0) if (source is null || Count == 0)
{ {
FactorEntry[] local = ArrayPool<FactorEntry>.Shared.Rent(1); FactorEntry[] local = ArrayPool<FactorEntry>.Shared.Rent(1);
local[0] = new FactorEntry(prime, 1); local[0] = new FactorEntry(prime, 1, true);
return Rent(local, 1UL, true, 1); return Rent(local, 1UL, true, 1, false);
} }
FactorEntry[] extended = ArrayPool<FactorEntry>.Shared.Rent(Count + 1); FactorEntry[] extended = ArrayPool<FactorEntry>.Shared.Rent(Count + 1);
Array.Copy(source, 0, extended, 0, Count); Array.Copy(source, 0, extended, 0, Count);
extended[Count] = new FactorEntry(prime, 1); extended[Count] = new FactorEntry(prime, 1, true);
Span<FactorEntry> span = extended.AsSpan(0, Count + 1); Span<FactorEntry> span = extended.AsSpan(0, Count + 1);
span.Sort(static (a, b) => a.Value.CompareTo(b.Value)); 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() public void Dispose()
+23 -27
View File
@@ -126,11 +126,11 @@ internal static partial class PrimeOrderCalculator
Span<FactorEntry> buffer = tempArray; Span<FactorEntry> buffer = tempArray;
factorSpan.CopyTo(buffer); factorSpan.CopyTo(buffer);
bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factors.Cofactor);
// bool isPrime = PrimeTester.IsPrimeInternal(factors.Cofactor, CancellationToken.None); // 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++; length++;
} }
@@ -190,14 +190,7 @@ internal static partial class PrimeOrderCalculator
if (!factorization.FullyFactored) if (!factorization.FullyFactored)
{ {
if (factorization.Cofactor <= 1UL) if (factorization.Cofactor <= 1UL || !factorization.CofactorIsPrime)
{
factorization.Dispose();
return false;
}
bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factorization.Cofactor);
if (!isPrime)
{ {
factorization.Dispose(); factorization.Dispose();
return false; return false;
@@ -281,9 +274,8 @@ internal static partial class PrimeOrderCalculator
return false; return false;
} }
var isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(orderFactors.Cofactor);
// if (!PrimeTester.IsPrimeInternal(orderFactors.Cofactor, CancellationToken.None)) // if (!PrimeTester.IsPrimeInternal(orderFactors.Cofactor, CancellationToken.None))
if (!isPrime) if (!orderFactors.CofactorIsPrime)
{ {
return false; return false;
} }
@@ -607,9 +599,9 @@ internal static partial class PrimeOrderCalculator
return false; 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); // bool isPrime = PrimeTester.IsPrimeInternal(factorization.Cofactor, CancellationToken.None);
if (!isPrime) if (!factorization.CofactorIsPrime)
{ {
return false; return false;
} }
@@ -839,9 +831,10 @@ internal static partial class PrimeOrderCalculator
ulong cofactor = 1UL; ulong cofactor = 1UL;
int pendingCount = pending.Count; 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); bool isPrime = GetOrComputePrimality(composite);
if (isPrime) if (isPrime)
@@ -856,33 +849,35 @@ internal static partial class PrimeOrderCalculator
} }
} }
bool cofactorIsPrime = GetOrComputePrimality(cofactor);
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool; ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
bool temp;
if (useDictionary) if (useDictionary)
{ {
if ((counts is null || counts.Count == 0) && cofactor == value) 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; goto ReturnResult;
} }
if (counts is null || counts.Count == 0) 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; goto ReturnResult;
} }
FactorEntry[] factors = pool.Rent(counts.Count); FactorEntry[] factors = pool.Rent(counts.Count);
int index = 0; index = 0;
foreach (KeyValuePair<ulong, int> entry in counts) foreach (KeyValuePair<ulong, int> entry in counts)
{ {
factors[index] = new FactorEntry(entry.Key, entry.Value); factors[index] = new FactorEntry(entry.Key, entry.Value, true);
index++; index++;
} }
Array.Sort(factors, static (a, b) => a.Value.CompareTo(b.Value)); Array.Sort(factors, static (a, b) => a.Value.CompareTo(b.Value));
bool fullyFactored = cofactor == 1UL; temp = cofactor == 1UL;
result = PartialFactorResult.Rent(factors, cofactor, fullyFactored, index); result = PartialFactorResult.Rent(factors, cofactor, temp, index, cofactorIsPrime);
goto ReturnResult; goto ReturnResult;
} }
@@ -912,14 +907,14 @@ internal static partial class PrimeOrderCalculator
// continue; // continue;
// } // }
array[arrayIndex] = new FactorEntry(primeValue, exponentValue); array[arrayIndex] = new FactorEntry(primeValue, exponentValue, true);
arrayIndex++; arrayIndex++;
} }
Span<FactorEntry> arraySpan = array.AsSpan(0, arrayIndex); Span<FactorEntry> arraySpan = array.AsSpan(0, arrayIndex);
arraySpan.Sort(static (a, b) => a.Value.CompareTo(b.Value)); arraySpan.Sort(static (a, b) => a.Value.CompareTo(b.Value));
bool fullyFactoredArray = cofactor == 1UL; temp = cofactor == 1UL;
result = PartialFactorResult.Rent(array, cofactor, fullyFactoredArray, arrayIndex); result = PartialFactorResult.Rent(array, cofactor, temp, arrayIndex, cofactorIsPrime);
ReturnResult: ReturnResult:
// ThreadStaticPools.UlongPool.Return(primeSlotsArray); // ThreadStaticPools.UlongPool.Return(primeSlotsArray);
@@ -1372,7 +1367,8 @@ internal static partial class PrimeOrderCalculator
return; return;
} }
if (Open.Numeric.Primes.Prime.Numbers.IsPrime(value)) // if (Open.Numeric.Primes.Prime.Numbers.IsPrime(value))
if (GetOrComputePrimality(value))
{ {
AddFactor(counts, value, 1); AddFactor(counts, value, 1);
return; return;