Merge pull request #63 from mlemanczyk/codex/remove-unused-local-variables-in-extensions
Rescope local declarations for divisor workflows
This commit is contained in:
4 files changed
+906
-834
No files matched your search
+637
-591
File diff suppressed because it is too large.
Load diff
@@ -96,26 +96,26 @@ public static class UInt128Extensions
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsPrimeCandidate(this UInt128 n)
|
||||
{
|
||||
UInt128 p, zero = UInt128.Zero;
|
||||
public static bool IsPrimeCandidate(this UInt128 n)
|
||||
{
|
||||
UInt128 p;
|
||||
|
||||
uint[] smallPrimes = PrimesGenerator.SmallPrimes;
|
||||
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
|
||||
ulong i, smallPrimesCount = (ulong)smallPrimes.Length;
|
||||
for (i = 0UL; i < smallPrimesCount; i++)
|
||||
{
|
||||
p = smallPrimes[i];
|
||||
if (smallPrimesPow2[i] > n)
|
||||
{
|
||||
break;
|
||||
}
|
||||
uint[] smallPrimes = PrimesGenerator.SmallPrimes;
|
||||
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
|
||||
ulong i, smallPrimesCount = (ulong)smallPrimes.Length;
|
||||
for (i = 0UL; i < smallPrimesCount; i++)
|
||||
{
|
||||
p = smallPrimes[i];
|
||||
if (smallPrimesPow2[i] > n)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (n % p == zero)
|
||||
{
|
||||
return n == p;
|
||||
}
|
||||
}
|
||||
if (n % p == UInt128.Zero)
|
||||
{
|
||||
return n == p;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -138,12 +138,11 @@ public static class UInt128Extensions
|
||||
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
||||
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
||||
|
||||
ulong parity = mod8 & 1UL;
|
||||
mod10 = parity == 0UL
|
||||
? mod5Value switch
|
||||
{
|
||||
0U => 0UL,
|
||||
1U => 6UL,
|
||||
mod10 = (mod8 & 1UL) == 0UL
|
||||
? mod5Value switch
|
||||
{
|
||||
0U => 0UL,
|
||||
1U => 6UL,
|
||||
2U => 2UL,
|
||||
3U => 8UL,
|
||||
_ => 4UL,
|
||||
@@ -184,16 +183,16 @@ public static class UInt128Extensions
|
||||
[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;
|
||||
UInt128 zero = UInt128.Zero;
|
||||
UInt128 result = UInt128.One;
|
||||
UInt128 baseValue = value % modulus;
|
||||
|
||||
while (exponent != zero)
|
||||
{
|
||||
if ((exponent & one) != zero)
|
||||
{
|
||||
result = MulMod(result, baseValue, modulus);
|
||||
}
|
||||
while (exponent != zero)
|
||||
{
|
||||
if ((exponent & UInt128.One) != zero)
|
||||
{
|
||||
result = MulMod(result, baseValue, modulus);
|
||||
}
|
||||
|
||||
baseValue = MulMod(baseValue, baseValue, modulus);
|
||||
exponent >>= 1;
|
||||
@@ -278,14 +277,15 @@ public static class UInt128Extensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static UInt128 MulMod(this UInt128 a, UInt128 b, UInt128 modulus)
|
||||
{
|
||||
UInt128 zero, result = zero = UInt128.Zero, one = UInt128.One;
|
||||
UInt128 zero = UInt128.Zero;
|
||||
UInt128 result = UInt128.Zero;
|
||||
|
||||
while (b != zero)
|
||||
{
|
||||
if ((b & one) != zero)
|
||||
{
|
||||
result += a;
|
||||
if (result >= modulus)
|
||||
while (b != zero)
|
||||
{
|
||||
if ((b & UInt128.One) != zero)
|
||||
{
|
||||
result += a;
|
||||
if (result >= modulus)
|
||||
{
|
||||
result -= modulus;
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ public static class UIntExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Mod10(this uint value)
|
||||
{
|
||||
uint quotient = (uint)(((ulong)value * 0xCCCCCCCDUL) >> 35);
|
||||
return value - quotient * 10U;
|
||||
return value - (uint)(((ulong)value * 0xCCCCCCCDUL) >> 35) * 10U;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
@@ -75,8 +75,7 @@ public static class ULongExtensions
|
||||
uint mod5Value = PerfectNumbersMath.FastRemainder5(byteSum);
|
||||
uint mod3Value = PerfectNumbersMath.FastRemainder3(byteSum);
|
||||
|
||||
ulong parity = mod8 & 1UL;
|
||||
mod10 = parity == 0UL
|
||||
mod10 = (mod8 & 1UL) == 0UL
|
||||
? mod5Value switch
|
||||
{
|
||||
0U => 0UL,
|
||||
@@ -137,10 +136,9 @@ public static class ULongExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Mod10(this ulong value)
|
||||
{
|
||||
ulong parity = value & 1UL;
|
||||
ulong mod5 = value.Mod5();
|
||||
|
||||
if (parity == 0UL)
|
||||
if ((value & 1UL) == 0UL)
|
||||
{
|
||||
return mod5 switch
|
||||
{
|
||||
@@ -265,253 +263,282 @@ public static class ULongExtensions
|
||||
public static ulong MulMod64(this ulong a, ulong b, ulong modulus) => (ulong)(UInt128)(((a % modulus) * (b % modulus)) % modulus);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static UInt128 PowMod(this ulong exponent, UInt128 modulus)
|
||||
{
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == 0UL)
|
||||
return UInt128.One;
|
||||
public static UInt128 PowMod(this ulong exponent, UInt128 modulus)
|
||||
{
|
||||
UInt128 result = UInt128.One;
|
||||
ulong exponentLoopIndex = 0UL;
|
||||
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == 0UL)
|
||||
return result;
|
||||
|
||||
UInt128 result;
|
||||
// For small exponents, do classic method
|
||||
if (exponent < 64 || modulus < 4)
|
||||
{
|
||||
result = UInt128.One;
|
||||
for (ulong i = 0; i < exponent; i++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
|
||||
return result;
|
||||
}
|
||||
// For small exponents, do classic method
|
||||
if (exponent < 64 || modulus < 4)
|
||||
{
|
||||
for (; exponentLoopIndex < exponent; exponentLoopIndex++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - 1)) == 0)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & 127);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// For general modulus, use classic left-to-right binary method for 2^exponent mod modulus
|
||||
UInt128 resultBin = UInt128.One;
|
||||
for (ulong i = 0; i < exponent; i++)
|
||||
{
|
||||
resultBin <<= 1;
|
||||
if (resultBin >= modulus)
|
||||
resultBin -= modulus;
|
||||
}
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - 1)) == 0)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & 127);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
|
||||
return resultBin;
|
||||
}
|
||||
// Reusing exponentLoopIndex to iterate again over the exponent range for the general-case accumulation.
|
||||
exponentLoopIndex = 0UL;
|
||||
// Reusing result after resetting it for the general modulus accumulation phase.
|
||||
result = UInt128.One;
|
||||
for (; exponentLoopIndex < exponent; exponentLoopIndex++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes 2^exponent mod modulus using a known cycle length.
|
||||
/// </summary>
|
||||
public static UInt128 PowModWithCycle(this ulong exponent, UInt128 modulus, ulong cycleLength)
|
||||
{
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == 0UL)
|
||||
return UInt128.One;
|
||||
public static UInt128 PowModWithCycle(this ulong exponent, UInt128 modulus, ulong cycleLength)
|
||||
{
|
||||
UInt128 result = UInt128.One;
|
||||
ulong exponentLoopIndex = 0UL;
|
||||
ulong rotationCount = 0UL;
|
||||
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == 0UL)
|
||||
return result;
|
||||
|
||||
// For small exponents, do classic method
|
||||
UInt128 result;
|
||||
if (exponent < 64 || modulus < 4)
|
||||
{
|
||||
result = UInt128.One;
|
||||
for (ulong i = 0; i < exponent; i++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
|
||||
return result;
|
||||
}
|
||||
// For small exponents, do classic method
|
||||
if (exponent < 64 || modulus < 4)
|
||||
{
|
||||
for (; exponentLoopIndex < exponent; exponentLoopIndex++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - 1)) == 0)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & 127);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// For general modulus, use classic left-to-right binary method for 2^exponent mod modulus
|
||||
result = UInt128.One;
|
||||
UInt128 rotations = exponent % cycleLength;
|
||||
for (ulong i = 0; i < rotations; i++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - 1)) == 0)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & 127);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
// Reusing exponentLoopIndex to iterate over the rotation count for the cycle-aware path.
|
||||
exponentLoopIndex = 0UL;
|
||||
// Reusing result after resetting it for the rotation-accumulation pass.
|
||||
result = UInt128.One;
|
||||
rotationCount = exponent % cycleLength;
|
||||
for (; exponentLoopIndex < rotationCount; exponentLoopIndex++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes 2^exponent mod modulus using a known cycle length.
|
||||
/// </summary>
|
||||
public static UInt128 PowModWithCycle(this ulong exponent, UInt128 modulus, UInt128 cycleLength)
|
||||
{
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == UInt128.Zero)
|
||||
return UInt128.One;
|
||||
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
public static UInt128 PowModWithCycle(this ulong exponent, UInt128 modulus, UInt128 cycleLength)
|
||||
{
|
||||
UInt128 result = UInt128.One;
|
||||
ulong exponentLoopIndex = 0UL;
|
||||
UInt128 rotationIndex = UInt128.Zero;
|
||||
UInt128 rotationCount = UInt128.Zero;
|
||||
|
||||
// For small exponents, do classic method
|
||||
UInt128 result;
|
||||
if (exponent < UInt128Numbers.SixtyFour || modulus < UInt128Numbers.Four)
|
||||
{
|
||||
result = UInt128.One;
|
||||
for (ulong i = 0; i < exponent; i++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == UInt128.Zero)
|
||||
return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - UInt128.One)) == UInt128.Zero)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & UInt128Numbers.OneHundredTwentySeven);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
// For small exponents, do classic method
|
||||
if (exponent < UInt128Numbers.SixtyFour || modulus < UInt128Numbers.Four)
|
||||
{
|
||||
for (; exponentLoopIndex < exponent; exponentLoopIndex++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
|
||||
// For general modulus, use classic left-to-right binary method for 2^exponent mod modulus
|
||||
result = UInt128.One;
|
||||
UInt128 rotations = exponent % cycleLength;
|
||||
for (UInt128 i = 0; i < rotations; i++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - UInt128.One)) == UInt128.Zero)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & UInt128Numbers.OneHundredTwentySeven);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
|
||||
// Reusing result after resetting it for the rotation-driven accumulation phase.
|
||||
result = UInt128.One;
|
||||
rotationCount = exponent % cycleLength;
|
||||
rotationIndex = UInt128.Zero;
|
||||
while (rotationIndex < rotationCount)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
|
||||
rotationIndex += UInt128.One;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes 2^exponent mod modulus using a known cycle length.
|
||||
/// </summary>
|
||||
public static UInt128 PowModWithCycle(this UInt128 exponent, UInt128 modulus, UInt128 cycleLength)
|
||||
{
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == UInt128.Zero)
|
||||
return UInt128.One;
|
||||
public static UInt128 PowModWithCycle(this UInt128 exponent, UInt128 modulus, UInt128 cycleLength)
|
||||
{
|
||||
UInt128 result = UInt128.One;
|
||||
ulong exponentLoopIndex = 0UL;
|
||||
UInt128 rotationIndex = UInt128.Zero;
|
||||
UInt128 rotationCount = UInt128.Zero;
|
||||
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
// Return 1 because 2^0 = 1
|
||||
if (exponent == UInt128.Zero)
|
||||
return result;
|
||||
|
||||
UInt128 result;
|
||||
// Any number mod 1 is 0
|
||||
if (modulus == UInt128.One)
|
||||
return UInt128.Zero;
|
||||
|
||||
// For small exponents, do classic method
|
||||
if (exponent < UInt128Numbers.SixtyFour || modulus < UInt128Numbers.Four)
|
||||
{
|
||||
result = UInt128.One;
|
||||
for (ulong i = 0; i < exponent; i++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
// For small exponents, do classic method
|
||||
if (exponent < UInt128Numbers.SixtyFour || modulus < UInt128Numbers.Four)
|
||||
{
|
||||
for (; exponentLoopIndex < exponent; exponentLoopIndex++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - UInt128.One)) == UInt128.Zero)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & UInt128Numbers.OneHundredTwentySeven);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
// Special case: if modulus is a power of two, use bitmasking for efficiency and correctness
|
||||
if ((modulus & (modulus - UInt128.One)) == UInt128.Zero)
|
||||
{
|
||||
result = UInt128.One << (int)(exponent & UInt128Numbers.OneHundredTwentySeven);
|
||||
return result & (modulus - 1);
|
||||
}
|
||||
|
||||
// For general modulus, use classic left-to-right binary method for 2^exponent mod modulus
|
||||
result = UInt128.One;
|
||||
UInt128 rotations = exponent % cycleLength;
|
||||
for (UInt128 i = 0; i < rotations; i++)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
}
|
||||
// Reusing result after resetting it for the rotation-driven accumulation phase.
|
||||
result = UInt128.One;
|
||||
rotationCount = exponent % cycleLength;
|
||||
rotationIndex = UInt128.Zero;
|
||||
while (rotationIndex < rotationCount)
|
||||
{
|
||||
result <<= 1;
|
||||
if (result >= modulus)
|
||||
result -= modulus;
|
||||
|
||||
return result;
|
||||
}
|
||||
rotationIndex += UInt128.One;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes 2^exponent mod modulus using iterative CRT composition from mod 10 up to modulus.
|
||||
/// Only for modulus >= 10 and reasonable size.
|
||||
/// </summary>
|
||||
public static UInt128 PowModCrt(this ulong exponent, UInt128 modulus, MersenneDivisorCycles cycles)
|
||||
{
|
||||
if (modulus < 10)
|
||||
return PowMod(exponent, modulus); // fallback to classic
|
||||
public static UInt128 PowModCrt(this ulong exponent, UInt128 modulus, MersenneDivisorCycles cycles)
|
||||
{
|
||||
if (modulus < 10)
|
||||
return PowMod(exponent, modulus); // fallback to classic
|
||||
|
||||
// Use cycle length 4 for mod 10
|
||||
UInt128 result = PowModWithCycle(exponent, 10, 4);
|
||||
// Use cycle length 4 for mod 10
|
||||
UInt128 result = PowModWithCycle(exponent, 10, 4);
|
||||
UInt128 currentModulus = 10;
|
||||
UInt128 modulusCandidate = 11;
|
||||
UInt128 cycle = UInt128.Zero;
|
||||
UInt128 remainderForCandidate = UInt128.Zero;
|
||||
|
||||
UInt128 currentModulus = 10;
|
||||
for (UInt128 m = 11; m <= modulus; m++)
|
||||
{
|
||||
UInt128 cycle = MersenneDivisorCycles.GetCycle(m);
|
||||
UInt128 remM = cycle > 0
|
||||
? PowModWithCycle(exponent, m, cycle)
|
||||
: PowMod(exponent, m);
|
||||
for (; modulusCandidate <= modulus; modulusCandidate++)
|
||||
{
|
||||
cycle = MersenneDivisorCycles.GetCycle(modulusCandidate);
|
||||
remainderForCandidate = cycle > UInt128.Zero
|
||||
? PowModWithCycle(exponent, modulusCandidate, cycle)
|
||||
: PowMod(exponent, modulusCandidate);
|
||||
|
||||
// Solve x ≡ result mod currentModulus
|
||||
// x ≡ remM mod m
|
||||
// Find x mod (currentModulus * m)
|
||||
// Since currentModulus and m are coprime, use CRT:
|
||||
// x = result + currentModulus * t, where t ≡ (remM - result) * inv(currentModulus, m) mod m
|
||||
// Solve x ≡ result mod currentModulus
|
||||
// x ≡ remM mod m
|
||||
// Find x mod (currentModulus * m)
|
||||
// Since currentModulus and m are coprime, use CRT:
|
||||
// x = result + currentModulus * t, where t ≡ (remM - result) * inv(currentModulus, m) mod m
|
||||
|
||||
UInt128 inv = ModInverse(currentModulus, m);
|
||||
UInt128 t = ((remM + m - (result % m)) * inv) % m;
|
||||
result += currentModulus * t;
|
||||
currentModulus *= m;
|
||||
result += currentModulus * ((remainderForCandidate + modulusCandidate - (result % modulusCandidate)) * ModInverse(currentModulus, modulusCandidate) % modulusCandidate);
|
||||
currentModulus *= modulusCandidate;
|
||||
|
||||
if (currentModulus >= modulus)
|
||||
break;
|
||||
}
|
||||
if (currentModulus >= modulus)
|
||||
break;
|
||||
}
|
||||
|
||||
return result % modulus;
|
||||
}
|
||||
return result % modulus;
|
||||
}
|
||||
|
||||
// Helper: modular inverse (extended Euclidean algorithm)
|
||||
private static UInt128 ModInverse(UInt128 a, UInt128 m)
|
||||
{
|
||||
UInt128 m0 = m, t, q;
|
||||
UInt128 x0 = 0, x1 = 1;
|
||||
if (m == 1) return 0;
|
||||
while (a > 1)
|
||||
{
|
||||
q = a / m;
|
||||
t = m;
|
||||
m = a % m; a = t;
|
||||
t = x0;
|
||||
x0 = x1 - q * x0;
|
||||
x1 = t;
|
||||
}
|
||||
// Helper: modular inverse (extended Euclidean algorithm)
|
||||
private static UInt128 ModInverse(UInt128 a, UInt128 m)
|
||||
{
|
||||
UInt128 m0 = m, temp;
|
||||
UInt128 x0 = 0, x1 = 1;
|
||||
UInt128 originalA = UInt128.Zero;
|
||||
UInt128 originalM = UInt128.Zero;
|
||||
if (m == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (x1 < 0) x1 += m0;
|
||||
while (a > 1)
|
||||
{
|
||||
originalA = a;
|
||||
originalM = m;
|
||||
m = originalA % originalM;
|
||||
a = originalM;
|
||||
temp = x0;
|
||||
x0 = x1 - (originalA / originalM) * x0;
|
||||
x1 = temp;
|
||||
}
|
||||
|
||||
return x1;
|
||||
}
|
||||
if (x1 < 0)
|
||||
{
|
||||
x1 += m0;
|
||||
}
|
||||
|
||||
return x1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool SharesFactorWithExponentMinusOne(this ulong exponent)
|
||||
|
||||
Reference in new issue
Block a user