Merge pull request #141 from mlemanczyk/codex/optimize-evenperfectbitscanner-cpu-path
Remove IDisposable from prime order scopes
This commit is contained in:
7 files changed
+157
-178
No files matched your search
@@ -279,17 +279,17 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
Console.WriteLine("Trying heuristic. Prime order calculation");
|
Console.WriteLine("Trying heuristic. Prime order calculation");
|
||||||
#endif
|
#endif
|
||||||
PrimeOrderCalculator.PrimeOrderResult orderResult = PrimeOrderCalculator.Calculate(
|
ulong order = PrimeOrderCalculator.Calculate(
|
||||||
modulus,
|
modulus,
|
||||||
_previousPrimeOrder,
|
_previousPrimeOrder,
|
||||||
divisorData,
|
divisorData,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
if (orderResult.Order != 0UL)
|
if (order != 0UL)
|
||||||
{
|
{
|
||||||
_previousPrimeOrder = orderResult.Order;
|
_previousPrimeOrder = order;
|
||||||
return orderResult.Order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
_previousPrimeOrder = null;
|
_previousPrimeOrder = null;
|
||||||
@@ -308,15 +308,15 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
Console.WriteLine("Trying heuristic. Wide prime order calculation");
|
Console.WriteLine("Trying heuristic. Wide prime order calculation");
|
||||||
#endif
|
#endif
|
||||||
PrimeOrderCalculator.PrimeOrderResultWide orderResult = PrimeOrderCalculator.Calculate(
|
UInt128 order = PrimeOrderCalculator.Calculate(
|
||||||
modulus,
|
modulus,
|
||||||
_previousWidePrimeOrder,
|
_previousWidePrimeOrder,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||||
|
|
||||||
if (orderResult.Order != UInt128.Zero)
|
if (order != UInt128.Zero)
|
||||||
{
|
{
|
||||||
_previousWidePrimeOrder = orderResult.Order;
|
_previousWidePrimeOrder = order;
|
||||||
return orderResult.Order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
_previousWidePrimeOrder = null;
|
_previousWidePrimeOrder = null;
|
||||||
|
|||||||
@@ -359,10 +359,9 @@ public class PrimeOrderGpuHeuristicsTests
|
|||||||
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
|
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
|
||||||
|
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime);
|
||||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
ulong result = PrimeOrderCalculator.Calculate(prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
result.Should().Be(3UL);
|
||||||
result.Order.Should().Be(3UL);
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,15 +45,14 @@ public class PrimeOrderCalculatorTests
|
|||||||
{
|
{
|
||||||
ulong expected = ComputeOrderByDoubling(prime);
|
ulong expected = ComputeOrderByDoubling(prime);
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(
|
ulong result = PrimeOrderCalculator.Calculate(
|
||||||
prime,
|
prime,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
MontgomeryDivisorData.FromModulus(prime),
|
MontgomeryDivisorData.FromModulus(prime),
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
result.Should().Be(expected);
|
||||||
result.Order.Should().Be(expected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -63,23 +62,21 @@ public class PrimeOrderCalculatorTests
|
|||||||
{
|
{
|
||||||
ulong previousOrder = ComputeOrderByDoubling(previousPrime);
|
ulong previousOrder = ComputeOrderByDoubling(previousPrime);
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResult heuristic = PrimeOrderCalculator.Calculate(
|
ulong heuristic = PrimeOrderCalculator.Calculate(
|
||||||
prime,
|
prime,
|
||||||
previousOrder,
|
previousOrder,
|
||||||
MontgomeryDivisorData.FromModulus(prime),
|
MontgomeryDivisorData.FromModulus(prime),
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResult strict = PrimeOrderCalculator.Calculate(
|
ulong strict = PrimeOrderCalculator.Calculate(
|
||||||
prime,
|
prime,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
MontgomeryDivisorData.FromModulus(prime),
|
MontgomeryDivisorData.FromModulus(prime),
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
heuristic.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
heuristic.Should().Be(strict);
|
||||||
strict.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
|
||||||
heuristic.Order.Should().Be(strict.Order);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -88,15 +85,14 @@ public class PrimeOrderCalculatorTests
|
|||||||
[InlineData(3UL, 2UL)]
|
[InlineData(3UL, 2UL)]
|
||||||
public void Calculate_handles_trivial_primes(ulong prime, ulong expectedOrder)
|
public void Calculate_handles_trivial_primes(ulong prime, ulong expectedOrder)
|
||||||
{
|
{
|
||||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(
|
ulong result = PrimeOrderCalculator.Calculate(
|
||||||
prime,
|
prime,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
MontgomeryDivisorData.FromModulus(prime),
|
MontgomeryDivisorData.FromModulus(prime),
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
result.Should().Be(expectedOrder);
|
||||||
result.Order.Should().Be(expectedOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -109,15 +105,14 @@ public class PrimeOrderCalculatorTests
|
|||||||
maxPowChecks: 8,
|
maxPowChecks: 8,
|
||||||
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
|
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(
|
ulong result = PrimeOrderCalculator.Calculate(
|
||||||
prime: 13UL,
|
prime: 13UL,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
MontgomeryDivisorData.FromModulus(13UL),
|
MontgomeryDivisorData.FromModulus(13UL),
|
||||||
config,
|
config,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.HeuristicUnresolved);
|
result.Should().Be(ComputeOrderByDoubling(13UL));
|
||||||
result.Order.Should().Be(ComputeOrderByDoubling(13UL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -131,15 +126,14 @@ public class PrimeOrderCalculatorTests
|
|||||||
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
|
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
|
||||||
|
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(239UL);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(239UL);
|
||||||
PrimeOrderCalculator.PrimeOrderResult heuristic = PrimeOrderCalculator.Calculate(
|
ulong heuristic = PrimeOrderCalculator.Calculate(
|
||||||
prime: 239UL,
|
prime: 239UL,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
divisorData,
|
divisorData,
|
||||||
heuristicConfig,
|
heuristicConfig,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
heuristic.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.HeuristicUnresolved);
|
heuristic.Should().Be(ComputeOrderByDoubling(239UL));
|
||||||
heuristic.Order.Should().Be(ComputeOrderByDoubling(239UL));
|
|
||||||
|
|
||||||
var strictConfig = new PrimeOrderCalculator.PrimeOrderSearchConfig(
|
var strictConfig = new PrimeOrderCalculator.PrimeOrderSearchConfig(
|
||||||
smallFactorLimit: 2,
|
smallFactorLimit: 2,
|
||||||
@@ -147,15 +141,14 @@ public class PrimeOrderCalculatorTests
|
|||||||
maxPowChecks: 1,
|
maxPowChecks: 1,
|
||||||
mode: PrimeOrderCalculator.PrimeOrderMode.Strict);
|
mode: PrimeOrderCalculator.PrimeOrderMode.Strict);
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResult strict = PrimeOrderCalculator.Calculate(
|
ulong strict = PrimeOrderCalculator.Calculate(
|
||||||
prime: 239UL,
|
prime: 239UL,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
divisorData,
|
divisorData,
|
||||||
strictConfig,
|
strictConfig,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
strict.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
strict.Should().Be(heuristic);
|
||||||
strict.Order.Should().Be(heuristic.Order);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -164,13 +157,12 @@ public class PrimeOrderCalculatorTests
|
|||||||
{
|
{
|
||||||
UInt128 prime = UInt128.Parse("18446744073709641691");
|
UInt128 prime = UInt128.Parse("18446744073709641691");
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResultWide result = PrimeOrderCalculator.Calculate(
|
UInt128 result = PrimeOrderCalculator.Calculate(
|
||||||
prime,
|
prime,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||||
|
|
||||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
result.Should().Be((UInt128)1229782938247309446UL);
|
||||||
result.Order.Should().Be((UInt128)1229782938247309446UL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -415,9 +415,9 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
ulong? previousOrder,
|
ulong? previousOrder,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig config,
|
PrimeOrderCalculator.PrimeOrderSearchConfig config,
|
||||||
in MontgomeryDivisorData divisorData,
|
in MontgomeryDivisorData divisorData,
|
||||||
out PrimeOrderCalculator.PrimeOrderResult result)
|
out ulong order)
|
||||||
{
|
{
|
||||||
result = default;
|
order = 0UL;
|
||||||
|
|
||||||
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
|
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
|
||||||
var execution = lease.EnterExecutionScope();
|
var execution = lease.EnterExecutionScope();
|
||||||
@@ -497,18 +497,17 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
throw new InvalidOperationException("GPU Pollard Rho stack overflow; increase HeuristicStackCapacity.");
|
throw new InvalidOperationException("GPU Pollard Rho stack overflow; increase HeuristicStackCapacity.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong order = 0UL;
|
|
||||||
resultBuffer.View.CopyToCPU(ref order, 1);
|
resultBuffer.View.CopyToCPU(ref order, 1);
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderStatus finalStatus = kernelStatus == PrimeOrderKernelStatus.Found
|
if (kernelStatus == PrimeOrderKernelStatus.FactoringFailure)
|
||||||
? PrimeOrderCalculator.PrimeOrderStatus.Found
|
{
|
||||||
: PrimeOrderCalculator.PrimeOrderStatus.HeuristicUnresolved;
|
order = 0UL;
|
||||||
|
}
|
||||||
|
|
||||||
result = new PrimeOrderCalculator.PrimeOrderResult(finalStatus, order);
|
|
||||||
DisposeResources();
|
DisposeResources();
|
||||||
lease.Dispose();
|
lease.Dispose();
|
||||||
|
|
||||||
return true;
|
return order != 0UL;
|
||||||
|
|
||||||
void DisposeResources()
|
void DisposeResources()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -234,14 +234,14 @@ public class MersenneDivisorCycles
|
|||||||
return (UInt128)cycle;
|
return (UInt128)cycle;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResultWide wideResult = PrimeOrderCalculator.Calculate(
|
UInt128 wideOrder = PrimeOrderCalculator.Calculate(
|
||||||
divisor,
|
divisor,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||||
if (wideResult.Order != UInt128.Zero)
|
if (wideOrder != UInt128.Zero)
|
||||||
{
|
{
|
||||||
return wideResult.Order;
|
return wideOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, find order of 2 mod divisor
|
// Otherwise, find order of 2 mod divisor
|
||||||
@@ -285,15 +285,15 @@ public class MersenneDivisorCycles
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimeOrderCalculator.PrimeOrderResult orderResult = PrimeOrderCalculator.Calculate(
|
ulong order = PrimeOrderCalculator.Calculate(
|
||||||
divisor,
|
divisor,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
divisorData,
|
divisorData,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||||
if (orderResult.Order != 0UL)
|
if (order != 0UL)
|
||||||
{
|
{
|
||||||
cycleLength = orderResult.Order;
|
cycleLength = order;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -940,15 +940,15 @@ public class MersenneDivisorCycles
|
|||||||
|
|
||||||
if (PrimeTester.IsPrimeInternal(divisor, CancellationToken.None))
|
if (PrimeTester.IsPrimeInternal(divisor, CancellationToken.None))
|
||||||
{
|
{
|
||||||
PrimeOrderCalculator.PrimeOrderResult orderResult = PrimeOrderCalculator.Calculate(
|
ulong order = PrimeOrderCalculator.Calculate(
|
||||||
divisor,
|
divisor,
|
||||||
previousOrder: null,
|
previousOrder: null,
|
||||||
divisorData,
|
divisorData,
|
||||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||||
if (orderResult.Order != 0UL)
|
if (order != 0UL)
|
||||||
{
|
{
|
||||||
cycleLength = orderResult.Order;
|
cycleLength = order;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,23 +9,10 @@ namespace PerfectNumbers.Core;
|
|||||||
|
|
||||||
internal static partial class PrimeOrderCalculator
|
internal static partial class PrimeOrderCalculator
|
||||||
{
|
{
|
||||||
internal readonly struct PrimeOrderResultWide
|
public static UInt128 Calculate(UInt128 prime, UInt128? previousOrder, PrimeOrderSearchConfig config)
|
||||||
{
|
|
||||||
public PrimeOrderResultWide(PrimeOrderStatus status, UInt128 order)
|
|
||||||
{
|
|
||||||
Status = status;
|
|
||||||
Order = order;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PrimeOrderStatus Status { get; }
|
|
||||||
|
|
||||||
public UInt128 Order { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PrimeOrderResultWide Calculate(UInt128 prime, UInt128? previousOrder, PrimeOrderSearchConfig config)
|
|
||||||
=> Calculate(prime, previousOrder, config, PrimeOrderHeuristicDevice.Gpu);
|
=> Calculate(prime, previousOrder, config, PrimeOrderHeuristicDevice.Gpu);
|
||||||
|
|
||||||
public static PrimeOrderResultWide Calculate(
|
public static UInt128 Calculate(
|
||||||
UInt128 prime,
|
UInt128 prime,
|
||||||
UInt128? previousOrder,
|
UInt128? previousOrder,
|
||||||
PrimeOrderSearchConfig config,
|
PrimeOrderSearchConfig config,
|
||||||
@@ -33,6 +20,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
var scope = UsePow2Mode(device);
|
var scope = UsePow2Mode(device);
|
||||||
MontgomeryDivisorData divisorData;
|
MontgomeryDivisorData divisorData;
|
||||||
|
UInt128 result;
|
||||||
if (prime <= ulong.MaxValue)
|
if (prime <= ulong.MaxValue)
|
||||||
{
|
{
|
||||||
ulong? previous = null;
|
ulong? previous = null;
|
||||||
@@ -51,50 +39,49 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
ulong prime64 = (ulong)prime;
|
ulong prime64 = (ulong)prime;
|
||||||
divisorData = MontgomeryDivisorData.FromModulus(prime64);
|
divisorData = MontgomeryDivisorData.FromModulus(prime64);
|
||||||
PrimeOrderResult result = Calculate(prime64, previous, divisorData, config, device);
|
ulong order64 = Calculate(prime64, previous, divisorData, config, device);
|
||||||
scope.Dispose();
|
result = order64 == 0UL ? UInt128.Zero : (UInt128)order64;
|
||||||
return new PrimeOrderResultWide(result.Status, result.Order);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
divisorData = default;
|
divisorData = default;
|
||||||
|
result = CalculateWideInternal(prime, previousOrder, divisorData, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimeOrderResultWide resultWide = CalculateWideInternal(prime, previousOrder, divisorData, config);
|
|
||||||
scope.Dispose();
|
scope.Dispose();
|
||||||
return resultWide;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PrimeOrderResultWide CalculateWideInternal(UInt128 prime, UInt128? previousOrder, in MontgomeryDivisorData divisorData, PrimeOrderSearchConfig config)
|
private static UInt128 CalculateWideInternal(UInt128 prime, UInt128? previousOrder, in MontgomeryDivisorData divisorData, PrimeOrderSearchConfig config)
|
||||||
{
|
{
|
||||||
if (prime <= UInt128.One)
|
if (prime <= UInt128.One)
|
||||||
{
|
{
|
||||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, UInt128.One);
|
return UInt128.One;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prime == (UInt128)3UL)
|
if (prime == (UInt128)3UL)
|
||||||
{
|
{
|
||||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, (UInt128)2UL);
|
return (UInt128)2UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 phi = prime - UInt128.One;
|
UInt128 phi = prime - UInt128.One;
|
||||||
var debugScope = UseDebugLogging(!IsGpuHeuristicDevice);
|
var debugScope = UseDebugLogging(!IsGpuHeuristicDevice);
|
||||||
PartialFactorResult128 phiFactors = PartialFactorWide(phi, config);
|
PartialFactorResult128 phiFactors = PartialFactorWide(phi, config);
|
||||||
PrimeOrderResultWide result;
|
UInt128 result;
|
||||||
if (phiFactors.Factors is null)
|
if (phiFactors.Factors is null)
|
||||||
{
|
{
|
||||||
// HeuristicFailureLog.Record(prime, null, HeuristicFailureReason.PhiPartialFactorizationFailed);
|
result = FinishStrictlyWide(prime, divisorData);
|
||||||
result = FinishStrictlyWide(prime, divisorData, config.Mode);
|
|
||||||
debugScope.Dispose();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
result = RunHeuristicPipelineWide(prime, previousOrder, divisorData, config, phi, phiFactors);
|
result = RunHeuristicPipelineWide(prime, previousOrder, divisorData, config, phi, phiFactors);
|
||||||
|
}
|
||||||
|
|
||||||
debugScope.Dispose();
|
debugScope.Dispose();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PrimeOrderResultWide RunHeuristicPipelineWide(
|
private static UInt128 RunHeuristicPipelineWide(
|
||||||
UInt128 prime,
|
UInt128 prime,
|
||||||
UInt128? previousOrder,
|
UInt128? previousOrder,
|
||||||
in MontgomeryDivisorData divisorData,
|
in MontgomeryDivisorData divisorData,
|
||||||
@@ -104,7 +91,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
if (phiFactors.FullyFactored && TrySpecialMaxWide(phi, prime, divisorData, phiFactors))
|
if (phiFactors.FullyFactored && TrySpecialMaxWide(phi, prime, divisorData, phiFactors))
|
||||||
{
|
{
|
||||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, phi);
|
return phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 candidateOrder = InitializeStartingOrderWide(prime, phi, divisorData);
|
UInt128 candidateOrder = InitializeStartingOrderWide(prime, phi, divisorData);
|
||||||
@@ -112,30 +99,25 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
if (TryConfirmOrderWide(prime, candidateOrder, divisorData, config))
|
if (TryConfirmOrderWide(prime, candidateOrder, divisorData, config))
|
||||||
{
|
{
|
||||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, candidateOrder);
|
return candidateOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.Mode == PrimeOrderMode.Strict)
|
if (config.Mode == PrimeOrderMode.Strict)
|
||||||
{
|
{
|
||||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.StrictModeRequested);
|
return FinishStrictlyWide(prime, divisorData);
|
||||||
return FinishStrictlyWide(prime, divisorData, PrimeOrderMode.Strict);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryHeuristicFinishWide(prime, candidateOrder, previousOrder, divisorData, config, out UInt128 order))
|
if (TryHeuristicFinishWide(prime, candidateOrder, previousOrder, divisorData, config, out UInt128 order))
|
||||||
{
|
{
|
||||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, order);
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.HeuristicPipelineAssumedFullOrder);
|
return candidateOrder;
|
||||||
// The heuristic pipeline could not narrow the order any further; assume the current order is final.
|
|
||||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, candidateOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PrimeOrderResultWide FinishStrictlyWide(UInt128 prime, in MontgomeryDivisorData divisorData, PrimeOrderMode mode)
|
private static UInt128 FinishStrictlyWide(UInt128 prime, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
UInt128 strictOrder = CalculateByFactorizationWide(prime, divisorData);
|
return CalculateByFactorizationWide(prime, divisorData);
|
||||||
PrimeOrderStatus status = mode == PrimeOrderMode.Strict ? PrimeOrderStatus.Found : PrimeOrderStatus.HeuristicUnresolved;
|
|
||||||
return new PrimeOrderResultWide(status, strictOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TrySpecialMaxWide(UInt128 phi, UInt128 prime, in MontgomeryDivisorData divisorData, PartialFactorResult128 factors)
|
private static bool TrySpecialMaxWide(UInt128 phi, UInt128 prime, in MontgomeryDivisorData divisorData, PartialFactorResult128 factors)
|
||||||
|
|||||||
@@ -18,24 +18,7 @@ namespace PerfectNumbers.Core;
|
|||||||
|
|
||||||
internal static partial class PrimeOrderCalculator
|
internal static partial class PrimeOrderCalculator
|
||||||
{
|
{
|
||||||
internal enum PrimeOrderStatus
|
|
||||||
{
|
|
||||||
Found,
|
|
||||||
HeuristicUnresolved,
|
|
||||||
}
|
|
||||||
|
|
||||||
internal readonly struct PrimeOrderResult
|
|
||||||
{
|
|
||||||
public PrimeOrderResult(PrimeOrderStatus status, ulong order)
|
|
||||||
{
|
|
||||||
Status = status;
|
|
||||||
Order = order;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PrimeOrderStatus Status { get; }
|
|
||||||
|
|
||||||
public ulong Order { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum PrimeOrderMode
|
internal enum PrimeOrderMode
|
||||||
{
|
{
|
||||||
@@ -167,7 +150,14 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PrimeOrderResult Calculate(
|
public static ulong Calculate(
|
||||||
|
ulong prime,
|
||||||
|
ulong? previousOrder,
|
||||||
|
in MontgomeryDivisorData divisorData,
|
||||||
|
in PrimeOrderSearchConfig config)
|
||||||
|
=> Calculate(prime, previousOrder, divisorData, config, PrimeOrderHeuristicDevice.Cpu);
|
||||||
|
|
||||||
|
public static ulong Calculate(
|
||||||
ulong prime,
|
ulong prime,
|
||||||
ulong? previousOrder,
|
ulong? previousOrder,
|
||||||
in MontgomeryDivisorData divisorData,
|
in MontgomeryDivisorData divisorData,
|
||||||
@@ -175,41 +165,36 @@ internal static partial class PrimeOrderCalculator
|
|||||||
PrimeOrderHeuristicDevice device)
|
PrimeOrderHeuristicDevice device)
|
||||||
{
|
{
|
||||||
var scope = UsePow2Mode(device);
|
var scope = UsePow2Mode(device);
|
||||||
PrimeOrderResult result = CalculateInternal(prime, previousOrder, divisorData, config);
|
ulong order = CalculateInternal(prime, previousOrder, divisorData, config);
|
||||||
scope.Dispose();
|
scope.Dispose();
|
||||||
return result;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PrimeOrderResult CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
private static ulong CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
||||||
{
|
{
|
||||||
if (prime <= 3UL)
|
if (prime <= 3UL)
|
||||||
{
|
{
|
||||||
return new PrimeOrderResult(PrimeOrderStatus.Found, prime == 3UL ? 2UL : 1UL);
|
return prime == 3UL ? 2UL : 1UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong phi = prime - 1UL;
|
ulong phi = prime - 1UL;
|
||||||
|
|
||||||
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(prime, previousOrder, config, divisorData, out PrimeOrderResult gpuResult))
|
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(prime, previousOrder, config, divisorData, out ulong gpuOrder))
|
||||||
{
|
{
|
||||||
return gpuResult;
|
return gpuOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
// using var debugScope = UseDebugLogging(!IsGpuHeuristicDevice);
|
|
||||||
// DebugLog("Partial factoring φ(p)");
|
|
||||||
|
|
||||||
using PartialFactorResult phiFactors = PartialFactor(phi, config);
|
using PartialFactorResult phiFactors = PartialFactor(phi, config);
|
||||||
|
|
||||||
if (phiFactors.Factors is null)
|
if (phiFactors.Factors is null)
|
||||||
{
|
{
|
||||||
// DebugLog("No factors found");
|
return FinishStrictly(prime, divisorData);
|
||||||
// HeuristicFailureLog.Record(prime, null, HeuristicFailureReason.PhiPartialFactorizationFailed);
|
|
||||||
return FinishStrictly(prime, divisorData, config.Mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return RunHeuristicPipeline(prime, previousOrder, config, divisorData, phi, phiFactors);
|
return RunHeuristicPipeline(prime, previousOrder, config, divisorData, phi, phiFactors);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PrimeOrderResult RunHeuristicPipeline(
|
private static ulong RunHeuristicPipeline(
|
||||||
ulong prime,
|
ulong prime,
|
||||||
ulong? previousOrder,
|
ulong? previousOrder,
|
||||||
in PrimeOrderSearchConfig config,
|
in PrimeOrderSearchConfig config,
|
||||||
@@ -217,44 +202,35 @@ internal static partial class PrimeOrderCalculator
|
|||||||
ulong phi,
|
ulong phi,
|
||||||
PartialFactorResult phiFactors)
|
PartialFactorResult phiFactors)
|
||||||
{
|
{
|
||||||
// DebugLog("Trying special max check");
|
|
||||||
if (phiFactors.FullyFactored && TrySpecialMax(phi, prime, phiFactors, divisorData))
|
if (phiFactors.FullyFactored && TrySpecialMax(phi, prime, phiFactors, divisorData))
|
||||||
{
|
{
|
||||||
return new PrimeOrderResult(PrimeOrderStatus.Found, phi);
|
return phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugLog("Initializing starting order");
|
|
||||||
ulong candidateOrder = InitializeStartingOrder(prime, phi, divisorData);
|
ulong candidateOrder = InitializeStartingOrder(prime, phi, divisorData);
|
||||||
candidateOrder = ExponentLowering(candidateOrder, prime, phiFactors, divisorData);
|
candidateOrder = ExponentLowering(candidateOrder, prime, phiFactors, divisorData);
|
||||||
|
|
||||||
// DebugLog("Trying to confirm order");
|
|
||||||
if (TryConfirmOrder(prime, candidateOrder, divisorData, config))
|
if (TryConfirmOrder(prime, candidateOrder, divisorData, config))
|
||||||
{
|
{
|
||||||
return new PrimeOrderResult(PrimeOrderStatus.Found, candidateOrder);
|
return candidateOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.Mode == PrimeOrderMode.Strict)
|
if (config.Mode == PrimeOrderMode.Strict)
|
||||||
{
|
{
|
||||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.StrictModeRequested);
|
return FinishStrictly(prime, divisorData);
|
||||||
return FinishStrictly(prime, divisorData, PrimeOrderMode.Strict);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryHeuristicFinish(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, out ulong order))
|
if (TryHeuristicFinish(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, out ulong order))
|
||||||
{
|
{
|
||||||
return new PrimeOrderResult(PrimeOrderStatus.Found, order);
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugLog("Heuristic unresolved, assuming current order");
|
return candidateOrder;
|
||||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.HeuristicPipelineAssumedFullOrder);
|
|
||||||
// The heuristic pipeline could not rule out additional divisors; assume the current order is final.
|
|
||||||
return new PrimeOrderResult(PrimeOrderStatus.Found, candidateOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PrimeOrderResult FinishStrictly(ulong prime, in MontgomeryDivisorData divisorData, PrimeOrderMode mode)
|
private static ulong FinishStrictly(ulong prime, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
ulong strictOrder = CalculateByFactorization(prime, divisorData);
|
return CalculateByFactorization(prime, divisorData);
|
||||||
PrimeOrderStatus status = mode == PrimeOrderMode.Strict ? PrimeOrderStatus.Found : PrimeOrderStatus.HeuristicUnresolved;
|
|
||||||
return new PrimeOrderResult(status, strictOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TrySpecialMax(ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
private static bool TrySpecialMax(ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
||||||
@@ -993,7 +969,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
if (value <= 1UL)
|
if (value <= 1UL)
|
||||||
{
|
{
|
||||||
return PartialFactorResult.Empty;
|
return PartialFactorResult.RentEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int FactorSlotCount = GpuSmallPrimeFactorSlots;
|
const int FactorSlotCount = GpuSmallPrimeFactorSlots;
|
||||||
@@ -1098,12 +1074,12 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
if ((counts is null || counts.Count == 0) && cofactor == value)
|
if ((counts is null || counts.Count == 0) && cofactor == value)
|
||||||
{
|
{
|
||||||
return new PartialFactorResult(null, value, false, 0);
|
return PartialFactorResult.Rent(null, value, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counts is null || counts.Count == 0)
|
if (counts is null || counts.Count == 0)
|
||||||
{
|
{
|
||||||
return new PartialFactorResult(null, cofactor, cofactor == 1UL, 0);
|
return PartialFactorResult.Rent(null, cofactor, cofactor == 1UL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FactorEntry[] factors = ArrayPool<FactorEntry>.Shared.Rent(counts.Count);
|
FactorEntry[] factors = ArrayPool<FactorEntry>.Shared.Rent(counts.Count);
|
||||||
@@ -1118,7 +1094,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
span.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
span.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
||||||
|
|
||||||
bool fullyFactored = cofactor == 1UL;
|
bool fullyFactored = cofactor == 1UL;
|
||||||
return new PartialFactorResult(factors, cofactor, fullyFactored, index, pooled: true);
|
return PartialFactorResult.Rent(factors, cofactor, fullyFactored, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
int actualCount = 0;
|
int actualCount = 0;
|
||||||
@@ -1134,10 +1110,10 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
if (cofactor == value)
|
if (cofactor == value)
|
||||||
{
|
{
|
||||||
return new PartialFactorResult(null, value, false, 0);
|
return PartialFactorResult.Rent(null, value, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartialFactorResult(null, cofactor, cofactor == 1UL, 0);
|
return PartialFactorResult.Rent(null, cofactor, cofactor == 1UL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FactorEntry[] array = ArrayPool<FactorEntry>.Shared.Rent(actualCount);
|
FactorEntry[] array = ArrayPool<FactorEntry>.Shared.Rent(actualCount);
|
||||||
@@ -1158,7 +1134,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
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;
|
bool fullyFactoredArray = cofactor == 1UL;
|
||||||
return new PartialFactorResult(array, cofactor, fullyFactoredArray, arrayIndex, pooled: true);
|
return PartialFactorResult.Rent(array, cofactor, fullyFactoredArray, arrayIndex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -1588,58 +1564,89 @@ internal static partial class PrimeOrderCalculator
|
|||||||
public readonly int Exponent = exponent;
|
public readonly int Exponent = exponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct PartialFactorResult : IDisposable
|
private sealed class PartialFactorResult : IDisposable
|
||||||
{
|
{
|
||||||
private FactorEntry[]? _factors;
|
[ThreadStatic]
|
||||||
private readonly bool _pooled;
|
private static PartialFactorResult? s_poolHead;
|
||||||
|
|
||||||
public PartialFactorResult(FactorEntry[]? factors, ulong cofactor, bool fullyFactored, int count, bool pooled = false)
|
private PartialFactorResult? _next;
|
||||||
|
private bool _returned;
|
||||||
|
|
||||||
|
public FactorEntry[]? Factors;
|
||||||
|
public ulong Cofactor;
|
||||||
|
public bool FullyFactored;
|
||||||
|
public int Count;
|
||||||
|
|
||||||
|
private PartialFactorResult()
|
||||||
{
|
{
|
||||||
_factors = factors;
|
|
||||||
Cofactor = cofactor;
|
|
||||||
FullyFactored = fullyFactored;
|
|
||||||
Count = count;
|
|
||||||
_pooled = pooled && factors is not null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FactorEntry[]? Factors => _factors;
|
public static PartialFactorResult Rent(FactorEntry[]? factors, ulong cofactor, bool fullyFactored, int count)
|
||||||
|
|
||||||
public ulong Cofactor { get; }
|
|
||||||
|
|
||||||
public bool FullyFactored { get; }
|
|
||||||
|
|
||||||
public int Count { get; }
|
|
||||||
|
|
||||||
public static PartialFactorResult Empty => new(null, 1UL, true, 0);
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
FactorEntry[]? factors = _factors;
|
PartialFactorResult? instance = s_poolHead;
|
||||||
if (factors is null || !_pooled)
|
if (instance is null)
|
||||||
{
|
{
|
||||||
return;
|
instance = new PartialFactorResult();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_poolHead = instance._next;
|
||||||
}
|
}
|
||||||
|
|
||||||
_factors = null;
|
instance._next = null;
|
||||||
ArrayPool<FactorEntry>.Shared.Return(factors, clearArray: false);
|
instance._returned = false;
|
||||||
|
instance.Factors = factors;
|
||||||
|
instance.Cofactor = cofactor;
|
||||||
|
instance.FullyFactored = fullyFactored;
|
||||||
|
instance.Count = count;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PartialFactorResult RentEmpty()
|
||||||
|
{
|
||||||
|
return Rent(null, 1UL, true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PartialFactorResult WithAdditionalPrime(ulong prime)
|
public PartialFactorResult WithAdditionalPrime(ulong prime)
|
||||||
{
|
{
|
||||||
if (_factors is null || Count == 0)
|
FactorEntry[]? source = Factors;
|
||||||
|
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);
|
||||||
return new PartialFactorResult(local, 1UL, true, 1, pooled: true);
|
return Rent(local, 1UL, true, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FactorEntry[] extended = ArrayPool<FactorEntry>.Shared.Rent(Count + 1);
|
FactorEntry[] extended = ArrayPool<FactorEntry>.Shared.Rent(Count + 1);
|
||||||
Array.Copy(_factors, 0, extended, 0, Count);
|
Array.Copy(source, 0, extended, 0, Count);
|
||||||
extended[Count] = new FactorEntry(prime, 1);
|
extended[Count] = new FactorEntry(prime, 1);
|
||||||
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 new PartialFactorResult(extended, 1UL, true, Count + 1, pooled: true);
|
return Rent(extended, 1UL, true, Count + 1);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_returned)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_returned = true;
|
||||||
|
|
||||||
|
FactorEntry[]? factors = Factors;
|
||||||
|
if (factors is not null)
|
||||||
|
{
|
||||||
|
Factors = null;
|
||||||
|
ArrayPool<FactorEntry>.Shared.Return(factors, clearArray: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cofactor = 0UL;
|
||||||
|
FullyFactored = false;
|
||||||
|
Count = 0;
|
||||||
|
|
||||||
|
_next = s_poolHead;
|
||||||
|
s_poolHead = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user