From 1978f7dfcb2c28086b582b63956467ba1b4ae3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Wed, 24 Sep 2025 00:32:15 +0200 Subject: [PATCH] Fix Mod10 shortcut and restore Mod10_8_5_3Steps accuracy --- ...MersenneNumberDivisorByDivisorGpuTester.cs | 127 +++++++++--------- PerfectNumbers.Core/ULongExtensions.cs | 52 +++---- 2 files changed, 91 insertions(+), 88 deletions(-) diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs index 496e10d..f73ad8c 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs @@ -335,84 +335,83 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester MersenneDivisorCycles? divisorCycles = useCycles ? MersenneDivisorCycles.Shared : null; ulong cycle = useCycles ? divisorCycles!.GetCycle(divisor) : 0UL, primeValue; MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor); - Span primeSpan = primesHost.AsSpan(0, gpuBatchSize); - ref ulong primesSpanRef = ref MemoryMarshal.GetReference(primeSpan); - Span indexSpan = indexHost.AsSpan(0, gpuBatchSize); - Span hitsSlice, hitSpan = hitsHost.AsSpan(0, gpuBatchSize); - ref byte hitSpanRef = ref MemoryMarshal.GetReference(hitSpan); - int batchSize, currentSpanSize = gpuBatchSize, gpuCount, i, primesLength = primes.Length; + Span primeSpan = Span.Empty; + Span indexSpan = Span.Empty; + Span hitSpan = Span.Empty; + Span hitsSlice; + int batchSize, currentSpanSize = -1, gpuCount, i, primesLength = primes.Length; while (offset < primesLength) { - batchSize = Math.Min(gpuBatchSize, primesLength - offset); - if (batchSize != currentSpanSize) - { - primeSpan = primesHost.AsSpan(0, batchSize); - primesSpanRef = ref MemoryMarshal.GetReference(primeSpan); - indexSpan = indexHost.AsSpan(0, batchSize); - hitSpan = hitsHost.AsSpan(0, batchSize); - hitSpanRef = ref MemoryMarshal.GetReference(hitSpan); - currentSpanSize = batchSize; - } + batchSize = Math.Min(gpuBatchSize, primesLength - offset); + ReadOnlySpan primesSlice = primes.Slice(offset, batchSize); - // We benefit from the constructor, because CopyTo will be called as static function - primes.Slice(offset, batchSize).CopyTo(primeSpan); + if (++consoleStatus == PerfectNumberConstants.ConsoleInterval) + { + Console.WriteLine($"...processed by-divisor candidate = {primesSlice[0]}"); + consoleStatus = 0; + } - if (++consoleStatus == PerfectNumberConstants.ConsoleInterval) - { - Console.WriteLine($"...processed by-divisor candidate = {primes[0]}"); - consoleStatus = 0; - } + hitsSlice = hits.Slice(offset, batchSize); - hitsSlice = hits.Slice(offset, batchSize); - gpuCount = 0; + if (useCycles) + { + if (batchSize != currentSpanSize) + { + primeSpan = primesHost.AsSpan(0, batchSize); + indexSpan = indexHost.AsSpan(0, batchSize); + hitSpan = hitsHost.AsSpan(0, batchSize); + currentSpanSize = batchSize; + } - if (useCycles) - { - for (i = 0; i < batchSize; i++) - { - primeValue = primeSpan[i]; - if (cycle == 0UL || primeValue % cycle != 0UL) - { - hitsSlice[i] = 0; - continue; - } + ref ulong primesSpanRef = ref MemoryMarshal.GetReference(primeSpan); + ref byte hitSpanRef = ref MemoryMarshal.GetReference(hitSpan); + gpuCount = 0; - indexSpan[gpuCount] = i; - primeSpan[gpuCount] = primeValue; - gpuCount++; - } + for (i = 0; i < batchSize; i++) + { + primeValue = primesSlice[i]; + if (cycle == 0UL || primeValue % cycle != 0UL) + { + hitsSlice[i] = 0; + continue; + } - if (gpuCount > 0) - { - primesView = primesBufferView.SubView(0, gpuCount); - hitsView = hitsBufferView.SubView(0, gpuCount); + indexSpan[gpuCount] = i; + primeSpan[gpuCount] = primeValue; + gpuCount++; + } - primesView.CopyFromCPU(ref primesSpanRef, gpuCount); - kernel(gpuCount, divisorData, primesView, hitsView); - accelerator.Synchronize(); + if (gpuCount > 0) + { + primesView = primesBufferView.SubView(0, gpuCount); + hitsView = hitsBufferView.SubView(0, gpuCount); - hitsView.CopyToCPU(ref hitSpanRef, gpuCount); - for (i = 0; i < gpuCount; i++) - { - hitsSlice[indexSpan[i]] = hitSpan[i]; - } - } - } - else - { - primesView = primesBufferView.SubView(0, batchSize); - hitsView = hitsBufferView.SubView(0, batchSize); + primesView.CopyFromCPU(ref primesSpanRef, gpuCount); + kernel(gpuCount, divisorData, primesView, hitsView); + accelerator.Synchronize(); - primesView.CopyFromCPU(ref primesSpanRef, batchSize); - kernel(batchSize, divisorData, primesView, hitsView); - accelerator.Synchronize(); + hitsView.CopyToCPU(ref hitSpanRef, gpuCount); + for (i = 0; i < gpuCount; i++) + { + hitsSlice[indexSpan[i]] = hitSpan[i]; + } + } + } + else + { + primesView = primesBufferView.SubView(0, batchSize); + hitsView = hitsBufferView.SubView(0, batchSize); - hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitSpan), batchSize); - hitSpan.CopyTo(hitsSlice); - } + ref ulong primesSliceRef = ref MemoryMarshal.GetReference(primesSlice); + primesView.CopyFromCPU(ref primesSliceRef, batchSize); + kernel(batchSize, divisorData, primesView, hitsView); + accelerator.Synchronize(); - offset += batchSize; + hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitsSlice), batchSize); + } + + offset += batchSize; } } diff --git a/PerfectNumbers.Core/ULongExtensions.cs b/PerfectNumbers.Core/ULongExtensions.cs index bc43055..7fadfa1 100644 --- a/PerfectNumbers.Core/ULongExtensions.cs +++ b/PerfectNumbers.Core/ULongExtensions.cs @@ -85,23 +85,27 @@ public static class ULongExtensions } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong Mod10(this ulong value) => (value & 1UL) == 0UL - ? value % 5UL switch - { - 0UL => 0UL, - 1UL => 6UL, - 2UL => 2UL, - 3UL => 8UL, - _ => 4UL, - } - : value % 5UL switch - { - 0UL => 5UL, - 1UL => 1UL, - 2UL => 7UL, - 3UL => 3UL, - _ => 9UL, - }; + public static ulong Mod10(this ulong value) + { + ulong mod5 = value % 5UL; + return (value & 1UL) == 0UL + ? mod5 switch + { + 0UL => 0UL, + 1UL => 6UL, + 2UL => 2UL, + 3UL => 8UL, + _ => 4UL, + } + : mod5 switch + { + 0UL => 5UL, + 1UL => 1UL, + 2UL => 7UL, + 3UL => 3UL, + _ => 9UL, + }; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Mod128(this ulong value) => value & 127UL; @@ -143,14 +147,14 @@ public static class ULongExtensions } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Mod10_8_5_3Steps(this ulong value, out ulong step10, out ulong step8, out ulong step5, out ulong step3) - { - value.Mod10_8_5_3(out step10, out step8, out step5, out step3); + public static void Mod10_8_5_3Steps(this ulong value, out ulong step10, out ulong step8, out ulong step5, out ulong step3) + { + value.Mod10_8_5_3(out step10, out step8, out step5, out step3); - step10 = (step10 << 1).Mod10(); - step8 = (step8 << 1) & 7UL; - step5 = (step5 << 1) % 5UL; - step3 = (step3 << 1) % 3UL; + step10 = (step10 << 1).Mod10(); + step8 = (step8 << 1) & 7UL; + step5 = (step5 << 1) % 5UL; + step3 = (step3 << 1) % 3UL; } [MethodImpl(MethodImplOptions.AggressiveInlining)]