diff --git a/PerfectNumbers.Core/MersenneNumberDivisorByDivisorTester.cs b/PerfectNumbers.Core/MersenneNumberDivisorByDivisorTester.cs index 92ced2b..3be9f82 100644 --- a/PerfectNumbers.Core/MersenneNumberDivisorByDivisorTester.cs +++ b/PerfectNumbers.Core/MersenneNumberDivisorByDivisorTester.cs @@ -38,34 +38,65 @@ public static class MersenneNumberDivisorByDivisorTester if (previousResults is not null && previousResults.Count > 0) { int recordedCount = previousResults.Count; - ulong[] recordedCandidates = ArrayPool.Shared.Rent(recordedCount); - try + bool preferSortedMerge = recordedCount <= 4096 || (recordedCount * 4L) <= candidateCount; + if (preferSortedMerge) { - Span recordedSpan = recordedCandidates.AsSpan(0, recordedCount); - int recordedIndex = 0; - foreach (ulong value in previousResults.Keys) + ulong[] recordedCandidates = ArrayPool.Shared.Rent(recordedCount); + try { - recordedSpan[recordedIndex++] = value; + Span recordedSpan = recordedCandidates.AsSpan(0, recordedCount); + int recordedIndex = 0; + foreach (ulong value in previousResults.Keys) + { + recordedSpan[recordedIndex++] = value; + } + + recordedSpan.Sort(); + + int writeIndex = 0; + int skipIndex = 0; + + for (int readIndex = 0; readIndex < candidateCount; readIndex++) + { + ulong candidate = candidateSpan[readIndex]; + + while (skipIndex < recordedCount && recordedSpan[skipIndex] < candidate) + { + skipIndex++; + } + + if (skipIndex < recordedCount && recordedSpan[skipIndex] == candidate) + { + skippedByPreviousResults++; + skipIndex++; + continue; + } + + candidateSpan[writeIndex++] = candidate; + } + + if (writeIndex < candidateCount) + { + candidates.RemoveRange(writeIndex, candidateCount - writeIndex); + candidateSpan = CollectionsMarshal.AsSpan(candidates); // candidateSpan now tracks the reduced list. + candidateCount = candidateSpan.Length; + } } - - recordedSpan.Sort(); - + finally + { + ArrayPool.Shared.Return(recordedCandidates, clearArray: true); + } + } + else + { int writeIndex = 0; - int skipIndex = 0; - for (int readIndex = 0; readIndex < candidateCount; readIndex++) { ulong candidate = candidateSpan[readIndex]; - while (skipIndex < recordedCount && recordedSpan[skipIndex] < candidate) - { - skipIndex++; - } - - if (skipIndex < recordedCount && recordedSpan[skipIndex] == candidate) + if (previousResults.ContainsKey(candidate)) { skippedByPreviousResults++; - skipIndex++; continue; } @@ -75,14 +106,10 @@ public static class MersenneNumberDivisorByDivisorTester if (writeIndex < candidateCount) { candidates.RemoveRange(writeIndex, candidateCount - writeIndex); - candidateSpan = CollectionsMarshal.AsSpan(candidates); + candidateSpan = CollectionsMarshal.AsSpan(candidates); // candidateSpan now tracks the reduced list. candidateCount = candidateSpan.Length; } } - finally - { - ArrayPool.Shared.Return(recordedCandidates, clearArray: true); - } } if (skippedByPreviousResults > 0)