Modular Inverse
ax + by = gcd(a, b),gcd(a, b) = 1时,ax + by = 1,ax = 1 (mod b),x = a^-1 (mod b),x即a的模逆。
Shifting
/// <summary>
/// <paramref name="value"/> ^ -1 (mod <paramref name="modulo"/>)
/// </summary>
public static BigInteger ModInverse(BigInteger value, BigInteger modulo)
{
if (modulo.Sign <= 0)
throw new ArithmeticException("modulo should be positive");
if (modulo.IsOne)
return BigInteger.Zero;
if (value.Sign < 0 || value >= modulo)
value = Mod(value, modulo);
if (value.IsOne)
return BigInteger.One;
var u = modulo; var v = value;
var r = BigInteger.Zero; var s = BigInteger.One;
var vLen = 0;
while ((vLen = v.BitLength()) > 1)
{
var shift = u.BitLength() - vLen;
if (u.Sign != v.Sign)
{
u += (v << shift);
r += (s << shift);
}
else
{
u -= (v << shift);
r -= (s << shift);
}
if (u.BitLength() < vLen)
{
Swap(ref u, ref v);
Swap(ref r, ref s);
}
}
if (v.IsZero) return BigInteger.MinusOne;//inverse does not exist
if (v.Sign < 0) s = -s;
if (s > modulo) s -= modulo;
if (s.Sign < 0) s += modulo;
return s;
}
/// <summary>
/// bit length of <see cref="BigInteger"/>
/// </summary>
public static int BitLength(this BigInteger value)
{
if (value.Sign < 0) value = -value;
var byteCount = value.GetByteCount();
var bitCount = (byteCount - 1) << 3;
value >>= bitCount;
return bitCount + 32 - ((uint)value).NumberOfLeadingZeros();
}
/// <summary>
/// <paramref name="value"/> (mod <paramref name="modulo"/>)
/// </summary>
public static BigInteger Mod(BigInteger value, BigInteger modulo)
{
if (modulo.Sign <= 0)
throw new ArithmeticException("modulo should be positive");
if (modulo.IsOne)
return BigInteger.Zero;
value = BigInteger.Remainder(value, modulo);
return value.Sign < 0 ? value + modulo : value;
}
public static void Swap<T>(ref T left, ref T right)
{
var temp = left;
left = right;
right = temp;
}
modular inverse of 2^k
/// <summary>
/// <paramref name="value"/> ^ -1 (mod 2 ^ <paramref name="k"/>)
/// assumes <paramref name="value"/> is odd.
/// </summary>
public static BigInteger ModInversePowerOf2(BigInteger value, int k)
{
if (value.IsEven)
throw new ArithmeticException("value should be odd");
var modulo = BigInteger.One << k;
var mod = value & (modulo - 1);
if (mod.Sign < 0) mod += modulo;
if (mod.IsOne) return 1;
var bits = new int[k];
var tmp = BigInteger.One;
for (var i = 0; i < k; ++i)
{
bits[i] = tmp.IsEven ? 0 : 1;
tmp = (tmp - (bits[i] == 0 ? 0 : mod)) >> 1;
}
var bytes = new byte[(k + 8) / 8];
for (int i = 0, j = 0, t = 0; i < bits.Length; i += 8, ++j)
{
t = 0;
for (var m = i; m < i + 8 && m < bits.Length; ++m)
t += (bits[m] << (m - i));
bytes[j] = (byte)(t & 0xFF);
}
return new BigInteger(bytes);
}