Add three-A-one-B schedule to combined tester
This commit is contained in:
1 parent
4c445f2a42
commit
465b40bf35
2 files changed
+115
-2
No files matched your search
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PerfectNumbers.Core;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace PerfectNumbers.Core.Tests;
|
||||
|
||||
public class HeuristicCombinedPrimeTesterTests
|
||||
{
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[InlineData((byte)1)]
|
||||
[InlineData((byte)7)]
|
||||
[InlineData((byte)9)]
|
||||
public void Enumerator_uses_three_a_one_b_schedule_by_default(byte lastDigit)
|
||||
{
|
||||
Span<HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState> groupBState =
|
||||
stackalloc HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState[4];
|
||||
|
||||
var enumerator = HeuristicCombinedPrimeTester.CreateHeuristicDivisorEnumerator(500, lastDigit, groupBState);
|
||||
var results = new List<HeuristicCombinedPrimeTester.HeuristicDivisorCandidate>(32);
|
||||
|
||||
while (results.Count < 20 && enumerator.TryGetNext(out var candidate))
|
||||
{
|
||||
results.Add(candidate);
|
||||
}
|
||||
|
||||
results.Count.Should().BeGreaterThanOrEqualTo(16);
|
||||
results[0].Value.Should().Be(3UL);
|
||||
results[0].Group.Should().Be(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupAConstant);
|
||||
results[1].Value.Should().Be(7UL);
|
||||
results[1].Group.Should().Be(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupAConstant);
|
||||
results[2].Value.Should().Be(11UL);
|
||||
results[2].Group.Should().Be(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupAConstant);
|
||||
results[3].Value.Should().Be(13UL);
|
||||
results[3].Group.Should().Be(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupAConstant);
|
||||
|
||||
int index = 4;
|
||||
const int segmentsToCheck = 3;
|
||||
|
||||
for (int segment = 0; segment < segmentsToCheck; segment++)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
HeuristicCombinedPrimeTester.HeuristicDivisorCandidate groupACandidate = results[index++];
|
||||
groupACandidate.Value.Should().BeGreaterThan(13UL);
|
||||
(groupACandidate.Value % 10UL).Should().Be(3UL);
|
||||
groupACandidate.Group.Should().NotBe(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupB);
|
||||
}
|
||||
|
||||
HeuristicCombinedPrimeTester.HeuristicDivisorCandidate groupBCandidate = results[index++];
|
||||
groupBCandidate.Value.Should().BeGreaterThan(13UL);
|
||||
(groupBCandidate.Value % 10UL).Should().NotBe(3UL);
|
||||
groupBCandidate.Group.Should().Be(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupB);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[InlineData((byte)1)]
|
||||
[InlineData((byte)7)]
|
||||
[InlineData((byte)9)]
|
||||
public void Three_a_one_b_pattern_interleaves_three_group_a_values_before_group_b(byte lastDigit)
|
||||
{
|
||||
ReadOnlySpan<uint> combined = HeuristicCombinedPrimeTester.GetCombinedDivisors(
|
||||
lastDigit,
|
||||
HeuristicCombinedPrimeTester.CombinedDivisorPattern.ThreeAOneB);
|
||||
|
||||
combined.Length.Should().BeGreaterThan(24);
|
||||
combined[0].Should().Be(3U);
|
||||
combined[1].Should().Be(7U);
|
||||
combined[2].Should().Be(11U);
|
||||
combined[3].Should().Be(13U);
|
||||
|
||||
int index = 4;
|
||||
const int segmentsToCheck = 4;
|
||||
|
||||
for (int segment = 0; segment < segmentsToCheck; segment++)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
uint groupAValue = combined[index++];
|
||||
groupAValue.Should().BeGreaterThan(13U);
|
||||
(groupAValue % 10U).Should().Be(3U);
|
||||
}
|
||||
|
||||
uint groupBValue = combined[index++];
|
||||
groupBValue.Should().BeGreaterThan(13U);
|
||||
(groupBValue % 10U).Should().NotBe(3U);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,12 +34,18 @@ public sealed class HeuristicCombinedPrimeTester
|
||||
private static readonly Lazy<uint[]> CombinedDivisorsEnding7OneAOneB = new(() => BuildCombinedDivisors(7, CombinedDivisorPattern.OneAOneB), LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
private static readonly Lazy<uint[]> CombinedDivisorsEnding9OneAOneB = new(() => BuildCombinedDivisors(9, CombinedDivisorPattern.OneAOneB), LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
|
||||
private static readonly Lazy<uint[]> CombinedDivisorsEnding1ThreeAOneB = new(() => BuildCombinedDivisors(1, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
private static readonly Lazy<uint[]> CombinedDivisorsEnding3ThreeAOneB = new(() => BuildCombinedDivisors(3, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
private static readonly Lazy<uint[]> CombinedDivisorsEnding7ThreeAOneB = new(() => BuildCombinedDivisors(7, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
private static readonly Lazy<uint[]> CombinedDivisorsEnding9ThreeAOneB = new(() => BuildCombinedDivisors(9, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
|
||||
private static readonly ulong[] HeuristicSmallCycleSnapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
|
||||
|
||||
internal enum CombinedDivisorPattern : byte
|
||||
{
|
||||
TwoAOneB = 0,
|
||||
OneAOneB = 1,
|
||||
ThreeAOneB = 2,
|
||||
}
|
||||
|
||||
internal enum HeuristicDivisorGroup : byte
|
||||
@@ -398,7 +404,7 @@ Cleanup:
|
||||
|
||||
private static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10)
|
||||
{
|
||||
return GetCombinedDivisors(nMod10, CombinedDivisorPattern.OneAOneB);
|
||||
return GetCombinedDivisors(nMod10, CombinedDivisorPattern.ThreeAOneB);
|
||||
}
|
||||
|
||||
internal static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern)
|
||||
@@ -421,6 +427,14 @@ Cleanup:
|
||||
9 => CombinedDivisorsEnding9OneAOneB.Value,
|
||||
_ => ReadOnlySpan<uint>.Empty,
|
||||
},
|
||||
CombinedDivisorPattern.ThreeAOneB => nMod10 switch
|
||||
{
|
||||
1 => CombinedDivisorsEnding1ThreeAOneB.Value,
|
||||
3 => CombinedDivisorsEnding3ThreeAOneB.Value,
|
||||
7 => CombinedDivisorsEnding7ThreeAOneB.Value,
|
||||
9 => CombinedDivisorsEnding9ThreeAOneB.Value,
|
||||
_ => ReadOnlySpan<uint>.Empty,
|
||||
},
|
||||
_ => ReadOnlySpan<uint>.Empty,
|
||||
};
|
||||
}
|
||||
@@ -440,7 +454,13 @@ Cleanup:
|
||||
}
|
||||
|
||||
int groupBIndex = GetGroupBStartIndex(groupB);
|
||||
int groupAInterleaveCount = pattern == CombinedDivisorPattern.OneAOneB ? 1 : 2;
|
||||
int groupAInterleaveCount = pattern switch
|
||||
{
|
||||
CombinedDivisorPattern.OneAOneB => 1,
|
||||
CombinedDivisorPattern.TwoAOneB => 2,
|
||||
CombinedDivisorPattern.ThreeAOneB => 3,
|
||||
_ => 2,
|
||||
};
|
||||
|
||||
while (groupAIndex < groupA.Length || groupBIndex < groupB.Length)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user