Merge pull request #63 from mlemanczyk/codex/remove-unused-local-variables-in-extensions

Rescope local declarations for divisor workflows
This commit is contained in:
Marek Lemańczyk authored and GitHub committed 2025-09-22 15:12:09 +02:00
commit 0195960b5a
4 files changed
+906 -834

No files matched your search

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