Как найти обратный модуль числа, т. Е. (% M), когда m не является простым

Я искал ответ на этот вопрос, я получил различные полезные ссылки, но когда я реализовал идею, я получаю неправильный ответ.

Вот что я понял:

Если m простое, то это очень просто. Обратный модуль любого числа "а" можно рассчитать как: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 - главные факторы м.

пусть 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" и "e 2", я использовал расширенный евклидов алгоритм. 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 ответа

Обратное a по модулю m существует только если a а также m взаимно просты Если они не взаимно просты, ничто не поможет. Например: что является обратным 2 модификация 4?

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

Так что нет обратного.

Это действительно может быть вычислено с использованием расширенного евклидова алгоритма (хотя я не уверен, правильно ли вы это делаете), но самый простой способ, на мой взгляд, заключается в использовании теоремы Эйлера:

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)

куда phi это общая функция:

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),

Возведение в степень может затем быть вычислено с использованием возведения в степень путем возведения в квадрат.

Если вы хотите прочитать о том, как вы можете использовать расширенный евклидов алгоритм, чтобы быстрее найти обратное, прочитайте это. Я не думаю, что китайская теорема об остатке может помочь здесь.

Я считаю, что следующая функция будет делать то, что вы хотите. Меняться от 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;
  }

Я не могу следовать вашему алгоритму, чтобы точно понять, что с ним не так, но у меня есть несколько общих замечаний: общая функция Эйлера вычисляется довольно медленно, в зависимости от простых факторизаций. Китайская теорема об остатках полезна во многих контекстах для комбинирования результатов модов, но в этом нет необходимости, здесь и снова усложняется эта конкретная проблема, потому что в конечном итоге вам приходится учитывать свой модуль, очень медленная операция. И быстрее реализовать GCD и модульную инверсию в цикле, чем использовать рекурсию, хотя, конечно, оба метода одинаково эффективны.

Если вы пытаетесь вычислить ^ (- 1) mod p ^ k для простого p, сначала вычислите ^ (- 1) mod p. Учитывая, что x такой, что ax = 1 (mod p ^ (k-1)), вы можете "поднять Hensel" --- вы ищете y между 0 и p-1, такой что a (x + yp ^ (к-1)) = 1 (мод р ^ к). Делая некоторую алгебру, вы обнаружите, что вы ищете y такой, что ayp ^ (k-1) = 1 - ax (mod p ^ k) --- т.е. ay = (1 - ax) / p ^ (k- 1) (mod p), где деление на p ^ (k-1) является точным. Вы можете решить это, используя модульное обратное для (мод p).

(В качестве альтернативы просто обратите внимание, что a ^ (p ^ (k-1) (p-1) - 1) = 1 (mod p ^ k). Я упоминаю подъем Хенселя, потому что он работает в гораздо большей общности.)

Другие вопросы по тегам