Add heuristic support for 128-bit prime orders
This commit is contained in:
1 parent
e6a80bb213
commit
07dad89fdf
4 files changed
+1108
-22
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@@ -142,6 +143,29 @@ public class PrimeOrderCalculatorTests
|
|||||||
strict.Order.Should().Be(heuristic.Order);
|
strict.Order.Should().Be(heuristic.Order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void Calculate_handles_128_bit_prime()
|
||||||
|
{
|
||||||
|
UInt128 prime = UInt128.Parse("18446744073709641691");
|
||||||
|
|
||||||
|
PrimeOrderCalculator.PrimeOrderResultWide result = PrimeOrderCalculator.Calculate(
|
||||||
|
prime,
|
||||||
|
previousOrder: null,
|
||||||
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||||
|
|
||||||
|
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||||
|
result.Order.Should().Be((UInt128)1229782938247309446UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Category", "Fast")]
|
||||||
|
public void GetCycle_uses_wide_prime_heuristic()
|
||||||
|
{
|
||||||
|
UInt128 prime = UInt128.Parse("18446744073709641691");
|
||||||
|
MersenneDivisorCycles.GetCycle(prime).Should().Be((UInt128)1229782938247309446UL);
|
||||||
|
}
|
||||||
|
|
||||||
private static ulong ComputeOrderByDoubling(ulong prime)
|
private static ulong ComputeOrderByDoubling(ulong prime)
|
||||||
{
|
{
|
||||||
if (prime == 2UL)
|
if (prime == 2UL)
|
||||||
|
|||||||
@@ -126,30 +126,48 @@ public class MersenneDivisorCycles
|
|||||||
return CalculateCycleLength(divisor);
|
return CalculateCycleLength(divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UInt128 GetCycle(UInt128 divisor)
|
public static UInt128 GetCycle(UInt128 divisor)
|
||||||
{
|
{
|
||||||
// For divisor = 2^k, cycle is 1
|
// For divisor = 2^k, cycle is 1
|
||||||
if ((divisor & (divisor - UInt128.One)) == UInt128.Zero)
|
if ((divisor & (divisor - UInt128.One)) == UInt128.Zero)
|
||||||
{
|
{
|
||||||
return UInt128.One;
|
return UInt128.One;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, find order of 2 mod divisor
|
if (divisor <= ulong.MaxValue)
|
||||||
// TODO: Port this UInt128 path to the unrolled-hex cycle calculator so wide
|
{
|
||||||
// divisors stop relying on the slow shift-and-subtract loop measured in the
|
ulong cycle = CalculateCycleLength((ulong)divisor);
|
||||||
// GPU benchmarks.
|
return (UInt128)cycle;
|
||||||
UInt128 order = UInt128.One, pow = UInt128Numbers.Two;
|
}
|
||||||
while (pow != UInt128.One)
|
|
||||||
{
|
|
||||||
pow <<= 1;
|
|
||||||
if (pow >= divisor)
|
|
||||||
pow -= divisor;
|
|
||||||
|
|
||||||
order++;
|
PrimeOrderCalculator.PrimeOrderResultWide wideResult = PrimeOrderCalculator.Calculate(
|
||||||
}
|
divisor,
|
||||||
|
previousOrder: null,
|
||||||
|
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||||
|
if (wideResult.Order != UInt128.Zero)
|
||||||
|
{
|
||||||
|
return wideResult.Order;
|
||||||
|
}
|
||||||
|
|
||||||
return order;
|
// Otherwise, find order of 2 mod divisor
|
||||||
}
|
// TODO: Port this UInt128 path to the unrolled-hex cycle calculator so wide
|
||||||
|
// divisors stop relying on the slow shift-and-subtract loop measured in the
|
||||||
|
// GPU benchmarks.
|
||||||
|
UInt128 order = UInt128.One;
|
||||||
|
UInt128 pow = UInt128Numbers.Two;
|
||||||
|
while (pow != UInt128.One)
|
||||||
|
{
|
||||||
|
pow <<= 1;
|
||||||
|
if (pow >= divisor)
|
||||||
|
{
|
||||||
|
pow -= divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool TryCalculateCycleLengthForExponent(
|
public static bool TryCalculateCycleLengthForExponent(
|
||||||
ulong divisor,
|
ulong divisor,
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -9,7 +9,7 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core;
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
internal static class PrimeOrderCalculator
|
internal static partial class PrimeOrderCalculator
|
||||||
{
|
{
|
||||||
internal enum PrimeOrderStatus
|
internal enum PrimeOrderStatus
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user