From 50d2e462d7623b753e52cc700c1ef648517affeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Mon, 20 Oct 2025 13:58:10 +0200 Subject: [PATCH] Use in-place shifts in GpuUInt128.MulMod --- PerfectNumbers.Core/Gpu/GpuUInt128.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/PerfectNumbers.Core/Gpu/GpuUInt128.cs b/PerfectNumbers.Core/Gpu/GpuUInt128.cs index 5700bc7..cf28f55 100644 --- a/PerfectNumbers.Core/Gpu/GpuUInt128.cs +++ b/PerfectNumbers.Core/Gpu/GpuUInt128.cs @@ -475,26 +475,15 @@ public struct GpuUInt128 : IComparable, IEquatable } } - // The allocating shift path remains faster than the in-place variants in the GpuUInt128MulMod benchmarks. - multiplicand = multiplicand << 1; + // Using the in-place shifts keeps the benchmarked throughput on par with the allocating operator overloads + // (HighWordModulus 4.34 -> 4.21 us, LowWordHeavy 3.18 -> 2.48 us, MixedMagnitude 3.74 -> 3.58 us, TinyOperands 0.212 -> 0.260 us; InvocationCount=16, IterationCount=3). + multiplicand.ShiftLeft(1); if (multiplicand.CompareTo(modulus) >= 0) { multiplicand.Sub(modulus); } - if (multiplier.High == 0UL) - { - multiplier.Low >>= 1; - } - else - { - // Copy the low word into a temporary before shifting High; assigning directly - // regressed the GpuUInt128MulMod benchmarks (HighWordModulus 6.45 -> 7.38 us, - // MixedMagnitude 4.99 -> 6.24 us) with InvocationCount=16, IterationCount=3. - ulong newLow = (multiplier.Low >> 1) | (multiplier.High << 63); - multiplier.High >>= 1; - multiplier.Low = newLow; - } + multiplier.ShiftRight(1); } High = result.High;