diff --git a/PerfectNumbers.Core.Tests/UInt128Extensions/UInt128ExtensionsTests.cs b/PerfectNumbers.Core.Tests/UInt128Extensions/UInt128ExtensionsTests.cs index d735285..875a568 100644 --- a/PerfectNumbers.Core.Tests/UInt128Extensions/UInt128ExtensionsTests.cs +++ b/PerfectNumbers.Core.Tests/UInt128Extensions/UInt128ExtensionsTests.cs @@ -112,6 +112,40 @@ public class UInt128ExtensionsTests mod3.Should().Be(expected3); } + [Theory] + [Trait("Category", "Fast")] + [InlineData(2UL, 0UL)] + [InlineData(2UL, 1UL)] + [InlineData(2UL, 63UL)] + [InlineData(2UL, 127UL)] + [InlineData(3UL, 5UL)] + public void Pow_matches_BigInteger(ulong value, ulong exponent) + { + UInt128 v = value; + UInt128 expected = (UInt128)BigPow(value, exponent); + + v.Pow(exponent).Should().Be(expected); + } + + private static BigInteger BigPow(ulong value, ulong exponent) + { + BigInteger result = BigInteger.One; + BigInteger baseValue = value; + + while (exponent != 0UL) + { + if ((exponent & 1UL) != 0UL) + { + result *= baseValue; + } + + baseValue *= baseValue; + exponent >>= 1; + } + + return result; + } + [Theory] [Trait("Category", "Fast")] [InlineData(2UL, 10UL, 17UL)] diff --git a/PerfectNumbers.Core/MersenneNumberTester.cs b/PerfectNumbers.Core/MersenneNumberTester.cs index e47c9b4..765cb69 100644 --- a/PerfectNumbers.Core/MersenneNumberTester.cs +++ b/PerfectNumbers.Core/MersenneNumberTester.cs @@ -214,7 +214,7 @@ public sealed class MersenneNumberTester( bool prePrime = true; UInt128 twoP = (UInt128)exponent << 1; // 2 * p // UInt128 maxDivisor = new(ulong.MaxValue, ulong.MaxValue); - UInt128 maxK = (UInt128Numbers.Two ^ exponent) / 2 + 1; + UInt128 maxK = UInt128Numbers.Two.Pow(exponent) / 2 + 1; bool lastIsSeven = (exponent & 3UL) == 3UL; // This is how maxK was for residue test before changes UInt128 maxK = maxKOverride ?? ResidueMaxK; diff --git a/PerfectNumbers.Core/UInt128Extensions.cs b/PerfectNumbers.Core/UInt128Extensions.cs index d8c93d1..78bca9f 100644 --- a/PerfectNumbers.Core/UInt128Extensions.cs +++ b/PerfectNumbers.Core/UInt128Extensions.cs @@ -150,15 +150,35 @@ public static class UInt128Extensions high >>= 64; } - mod10 = result % 10UL; - } + mod10 = result % 10UL; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static UInt128 ModPow(this UInt128 value, UInt128 exponent, UInt128 modulus) - { - UInt128 result, one = result = UInt128.One, - zero = UInt128.Zero, - baseValue = value % modulus; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static UInt128 Pow(this UInt128 value, ulong exponent) + { + UInt128 result = UInt128.One; + UInt128 baseValue = value; + + while (exponent != 0UL) + { + if ((exponent & 1UL) != 0UL) + { + result *= baseValue; + } + + baseValue *= baseValue; + exponent >>= 1; + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static UInt128 ModPow(this UInt128 value, UInt128 exponent, UInt128 modulus) + { + UInt128 result, one = result = UInt128.One, + zero = UInt128.Zero, + baseValue = value % modulus; while (exponent != zero) {