当m不是素数时,如何找到一个数的逆模数,即(a%m)

时间:2015-06-14 17:45:29

标签: algorithm modulus chinese-remainder-theorem

我搜索了这个问题的答案,我得到了各种有用的链接但是当我实现这个想法时,我得到了错误的答案。

这就是我所理解的:

如果m是素数,则非常简单。任何数字'a'的逆模数可以计算为:inverse_mod(a) = (a^(m-2))%m

但是当m不是素数时,我们必须找到m的素因子, 即m= (p1^a1)*(p2^a2)*....*(pk^ak).这里p1,p2,....,pk是m的主要因子,a1,a2,....,ak是它们各自的权力。

然后我们必须计算:

m1 = a%(p1^a1),

m2 = a%(p2^a2), 

.......

mk = a%(pk^ak)

然后我们必须使用中国剩余定理https://en.wikipedia.org/wiki/Chinese_remainder_theorem

组合所有这些余数

我实现了m = 1000,000,000的这个想法,但我仍然得到了错误的答案。

这是我对m = 1000,000,000的解释,这不是素数

m= (2^9)*(5^9)其中2和5是m的主要因素。

设a是必须计算逆模m的数字。

m1 = a%(2^9) = a^512

m2 = a%(5^9) = a^1953125

Our answer will be = m1*e1 + m2*e2

where e1= {  1 (mod 512)

             0 (mod 1953125)
          }
  and e2= {     1 (mod 1953125)

                0 (mod 512)
           } 

现在计算'e1'和'e2',我使用扩展欧几里德算法https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm

守则是:

    void extend_euclid(lld a,lld b,lld& x,lld& y)
    {
          if(a%b==0)
          {
             x=0;
             y=1;
             return ;
          }
          extend_euclid(b,a%b,x,y);
          int tmp=x;
          x=y;
          y=tmp-(a/b)*y;
    }

Now e1= 1953125*y and e2=512*y;

So, Our final answer will be = m1*e1 + m2*e2 .

但是在完成所有这些之后,我得到了错误的回答。

请解释并指出我在理解中国剩余定理时所犯的任何错误。

非常感谢。

3 个答案:

答案 0 :(得分:2)

如果amcoprimeam的倒数仅存在。如果它们不是互质的,那么没有什么能帮到你。例如:2 mod 4的反转是什么?

2*0 = 0 mod 4
2*1 = 2 mod 4
2*2 = 0 mod 4
2*3 = 2 mod 4

所以没有反过来。

这确实可以通过使用扩展的欧几里德算法来计算(虽然我不确定你是否做得对),但在我看来,最简单的方法是使用{{3} }:

a^phi(m) = 1 (mod m)
a*a^(phi(m) - 1) = 1 (mod m)
=> a^(phi(m) - 1) is the invers of a (mod m)

其中phiEuler's theorem

phi(x) = x * (1 - 1/f1)(1 - 1/f2)...(1 - 1/fk)
where fi > 1 is a divisor of x (not necessarily a prime divisor)

phi(36) = 36(1 - 1/2)(1 - 1/3)(1 - 1/4)(1 - 1/6)(1 - 1/9)(1 - 1/12)(1 - 1/18)(1 - 1/36)

因此可以在O(sqrt n)中计算出来。

然后可以使用totient function计算取幂。

如果您想了解如何使用扩展的欧几里德算法更快地找到逆,请阅读exponentiation by squaring。我不认为中国剩余定理可以在这里提供帮助。

答案 1 :(得分:0)

如果你想为p prime计算^( - 1)mod p ^ k,首先计算一个^( - 1)mod p。给定一个x,使得ax = 1(mod p ^(k-1)),你可以“Hensel lift”---你正在寻找0和p-1之间的y,这样a(x + yp ^( k-1))= 1(mod p ^ k)。做一些代数,你会发现你正在寻找y,使得y p ^(k-1)= 1 - ax(mod p ^ k)---即。 a y =(1-ax)/ p ^(k-1)(mod p),其中除以p ^(k-1)是精确的。您可以使用(mod p)的模块化逆转来解决这个问题。

(或者,只需注意一个^(p ^(k-1)(p-1) - 1)= 1(mod p ^ k)。我提到Hensel提升,因为它的工作原理更为普遍。)< / p>

答案 2 :(得分:0)

我相信以下功能会做你想要的。如果合适,请从long更改为int。如果没有反转则返回-1,否则返回[0..m)范围内的正数。

  public static long inverse(long a, long m) { // mult. inverse of a mod m
    long r = m;
    long nr = a;
    long t = 0;
    long nt = 1;
    long tmp;
    while (nr != 0) {
      long q = r/nr;
      tmp = nt; nt = t - q*nt; t = tmp;
      tmp = nr; nr = r - q*nr; r = tmp;
    }
    if (r > 1) return -1; // no inverse
    if (t < 0) t += m;
    return t;
  }

我不能按照你的算法来确切地看到它有什么问题,但我有一些一般性评论:Euler的totient函数通常计算起来相当慢,这取决于它在主要因素分析上的作用。中国剩余定理在许多情况下用于组合结果mod互质是有用的,但是这里并不是必须使这个特定问题过于复杂,因为你最终必须考虑你的模数,这是一个非常慢的操作。并且在循环中实现GCD和模块化逆转更快,而不是使用递归,尽管这两种方法当然同样有效。