【问题标题】:C# ModInverse FunctionC# ModInverse 函数
【发布时间】:2011-11-20 23:21:48
【问题描述】:

是否有一个内置函数可以让我计算 a(mod n) 的模逆? 例如19^-1 = 11 (mod 30),在这种情况下 19^-1 == -11==19;

【问题讨论】:

  • 请注意,您可以反转任意乘法。例如,由于 GCD(2,30)!=1,2 具有乘法逆模 30

标签: c# c#-4.0 modulo


【解决方案1】:

由于 .Net 4.0+ 使用特殊的模运算函数 ModPow 实现 BigInteger(产生“X power Y modulo Z”),因此您不需要第三方库来模拟 ModInverse。如果n 是素数,那么您只需计算:

a_inverse = BigInteger.ModPow(a, n - 2, n)

有关更多详细信息,请查看 Wikipedia:Modular multiplicative inverseUsing Euler's theorem 部分,特殊情况“当 m 是质数时”。顺便说一句,最近有一个关于此的 SO 主题:1/BigInteger in c#,使用相同的方法 suggested by CodesInChaos

【讨论】:

  • 请注意这是特殊情况,当 m 是素数时
【解决方案2】:
int modInverse(int a, int n) 
{
    int i = n, v = 0, d = 1;
    while (a>0) {
        int t = i/a, x = a;
        a = i % x;
        i = x;
        x = d;
        d = v - t*x;
        v = x;
    }
    v %= n;
    if (v<0) v = (v+n)%n;
    return v;
}

【讨论】:

  • 似乎可以工作,但是如果它可以发出信号(例如,通过抛出异常)如果逆是不可能的(a 是不可逆的模 n),那会很好,当@987654324 发生时@ 和 n 共享一个重要因素(他们的 GCD 超过 1)。
【解决方案3】:

BouncyCastle Crypto 库有一个 BigInteger 实现,它具有大多数模块化算术函数。它位于 Org.BouncyCastle.Math 命名空间中。

【讨论】:

    【解决方案4】:

    这里是 Samuel Allan 的algorithm 稍微完善的版本。 TryModInverse 方法返回一个 bool 值,该值指示此数和模是否存在模乘逆。

    public static bool TryModInverse(int number, int modulo, out int result)
    {
        if (number < 1) throw new ArgumentOutOfRangeException(nameof(number));
        if (modulo < 2) throw new ArgumentOutOfRangeException(nameof(modulo));
        int n = number;
        int m = modulo, v = 0, d = 1;
        while (n > 0)
        {
            int t = m / n, x = n;
            n = m % x;
            m = x;
            x = d;
            d = checked(v - t * x); // Just in case
            v = x;
        }
        result = v % modulo;
        if (result < 0) result += modulo;
        if ((long)number * result % modulo == 1L) return true;
        result = default;
        return false;
    }
    

    【讨论】:

      【解决方案5】:

      没有获取逆模的库,但是可以通过以下代码获取。

      // Given a and b->ax+by=d
      long[] u = { a, 1, 0 };
      long[] v = { b, 0, 1 };
      long[] w = { 0, 0, 0 };
      long temp = 0;
      while (v[0] > 0)
      {
          double t = (u[0] / v[0]);
          for (int i = 0; i < 3; i++)
          {
              w[i] = u[i] - ((int)(Math.Floor(t)) * v[i]);
              u[i] = v[i];
              v[i] = w[i];
          }
      }
      // u[0] is gcd while u[1] gives x and u[2] gives y. 
      // if u[1] gives the inverse mod value and if it is negative then the following gives the first positive value
      if (u[1] < 0)
      {
              while (u[1] < 0)
              {
                  temp = u[1] + b;
                  u[1] = temp;
              }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-05-11
        • 2018-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-01
        相关资源
        最近更新 更多