1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9

# теория · шаг 3 из 9

Расширенный Евклид и обратный элемент: как делить по модулю

Коротко

Делить по модулю - значит умножать на обратный элемент: число x, для которого a · x ≡ 1 (mod m). Обратный к 7 по модулю 40 - это 23, потому что 7 · 23 = 161 = 4 · 40 + 1. Он существует тогда и только тогда, когда a и m взаимно просты. Находит его расширенный алгоритм Евклида: тот же цикл, который вдобавок к НОД ведёт два коэффициента и в конце выдаёт x и y с a · x + m · y = НОД(a, m). Цена - те же несколько кругов на цифру: обратный к 123 456 по модулю 1 000 003 найден за 120 шагов. По простому модулю обратный есть у каждого ненулевого остатка.

Если ты найдёшь обратный элемент расширенным алгоритмом Евклида, объяснишь, почему у 6 нет обратного по модулю 9, и решишь сравнение 7x ≡ 5 (mod 40), - листай до «Теперь сам».

Как думаешь, как найти x

Нужно число x, для которого 7 · x при делении на 40 даёт остаток 1. Можно перебрать все x от 1 до 39 и проверить каждое - до тридцати девяти проб, и 23 найдётся.

Прежде чем читать дальше, ответь себе на два вопроса. Что делать, если модуль - не 40, а число из шестисот цифр, и перебор отпадает? И всегда ли такое x вообще существует - например, есть ли x, для которого 6 · x даёт остаток 1 при делении на 9?

На что это похоже

Представь два ведра - на 40 литров и на 7 - и бочку, в которой надо оставить ровно один литр. Воду можно наливать в бочку полными вёдрами и вычерпывать полными вёдрами.

Решение: три раза налить ведром на 40 и семнадцать раз вычерпать ведром на 7. 3 · 40 − 17 · 7 = 120 − 119 = 1. Вёдрами на 6 и на 9 литров один литр не получить никак: что ни наливай и ни вычерпывай, в бочке будет число литров, кратное трём.

Обратный элемент - это ответ на вопрос «сколько раз черпать». А существует он ровно тогда, когда вёдрами можно отмерить единицу.

Механизм: вести коэффициенты вместе с остатками

Обычный Евклид на каждом круге получает новый остаток: r = a − q · b. Каждый остаток, таким образом, собран из исходных чисел сложением и вычитанием. Расширенный алгоритм записывает, как именно: для каждого числа в цепочке он помнит пару (x, y), такую что число равно x · a₀ + y · b₀, где a₀ и b₀ - исходные числа.

Начало известно: a₀ = 1 · a₀ + 0 · b₀, пара (1, 0); b₀ = 0 · a₀ + 1 · b₀, пара (0, 1). Новый остаток равен старому числу минус q раз следующее - и его пара получается так же: старая пара минус q раз следующая.

числа 40 и 7                              каждая строка: число = x · 40 + y · 7

число    q        x      y         проверка
 40               1      0         1 · 40 + 0 · 7
  7      5        0      1         0 · 40 + 1 · 7
  5      1        1     −5         40 − 5 · 7 = 5
  2      2       −1      6         −40 + 6 · 7 = 2
  1      2        3    −17         3 · 40 − 17 · 7 = 1
  0

Столбец q - частное от деления числа строкой выше на число в этой строке. Пара каждой новой строки - пара двумя строками выше минус q из строки выше, умноженное на пару строкой выше: для числа 5 это (1, 0) − 5 · (0, 1) = (1, −5). Последнее ненулевое число - НОД, а его пара - искомые коэффициенты: 3 · 40 − 17 · 7 = 1.

Теперь возьми это равенство по модулю 40. Слагаемое 3 · 40 исчезает, остаётся −17 · 7 ≡ 1. Значит −17 - обратный к 7, и в привычном виде это −17 + 40 = 23. Обратный - коэффициент при том числе, к которому его ищут: в таблице это y, коэффициент при семёрке.

Обратный элемент к a по модулю m - число x от 1 до m − 1, для которого a · x ≡ 1 (mod m). Пишут a⁻¹. Разделить на a по модулю - значит умножить на a⁻¹.

Правило

Для любых целых a и b существуют целые x и y, такие что a · x + b · y = НОД(a, b); расширенный алгоритм Евклида находит их за то же число кругов, что и НОД. Обратный к a по модулю m существует тогда и только тогда, когда НОД(a, m) = 1, и равен коэффициенту при a, приведённому к диапазону от 0 до m − 1. Сравнение a · x ≡ b (mod m) при НОД(a, m) = g имеет решения, только если b делится на g, и тогда решений по модулю m ровно g.

Почему «только когда НОД равен единице». Если a · x ≡ 1 (mod m), то a · x − k · m = 1 для какого-то k. Любой общий делитель a и m делит левую часть, значит делит единицу. Общих делителей, кроме единицы, быть не может.

Разбор: программа и деление

def rasshirennyj(a, b):
    x0 = 1
    y0 = 0
    x1 = 0
    y1 = 1
    while b != 0:
        q = a // b
        r = a - q * b
        a = b
        b = r
        x2 = x0 - q * x1
        x0 = x1
        x1 = x2
        y2 = y0 - q * y1
        y0 = y1
        y1 = y2
    return [a, x0, y0]

def obratnyj(a, m):
    r = rasshirennyj(a, m)
    if r[0] != 1:
        return -1
    return r[1] % m

Пары (x0, y0) и (x1, y1) - коэффициенты для текущих a и b; каждый круг сдвигает их вместе с числами. rasshirennyj(7, 40) возвращает [1, -17, 3] - НОД и коэффициенты при 7 и при 40, в порядке аргументов, - а obratnyj(7, 40) возвращает одно число, 23: остаток в Python приводит −17 к диапазону от 0 до 39.

Ответ на первый вопрос из начала урока: перебор не нужен. obratnyj(123456, 1000003) возвращает 414 894 за 120 шагов тренажёра. Перебор сделал бы до миллиона проб.

Теперь деление. Решим 7 · x ≡ 5 (mod 40). Умножим обе части на обратный к 7: x ≡ 5 · 23 = 115 ≡ 35. Проверка: 7 · 35 = 245 = 6 · 40 + 5. Умножение на обратный сделало то, что в обычной арифметике делает деление на 7.

Разбор: когда обратного нет

rasshirennyj(6, 9) возвращает [3, -1, 1]: НОД равен трём, 6 · (−1) + 9 · 1 = 3. Единицу из шестёрок и девяток не собрать - obratnyj(6, 9) возвращает −1, признак отказа. Это ответ на второй вопрос.

Но сравнение с шестёркой иногда решается. 6 · x ≡ 3 (mod 9): правая часть делится на НОД. Раздели всё на три - и числа, и модуль: 6x − 3 делится на 9 ровно тогда, когда 2x − 1 делится на 3. Получается 2 · x ≡ 1 (mod 3); обратный к 2 по модулю 3 - это 2, откуда x ≡ 2 (mod 3). По модулю 9 это три решения: 2, 5 и 8. Проверка: 12, 30 и 48 дают остаток 3. А у 6 · x ≡ 4 (mod 9) решений нет: слева всегда число, кратное трём, по модулю девять - 0, 3 или 6.

Кто обратим, зависит от модуля:

модуль 7:    a      1  2  3  4  5  6          модуль 12:   a      1  5  7  11
             a⁻¹    1  4  5  2  3  6                       a⁻¹    1  5  7  11
                                              у 2, 3, 4, 6, 8, 9, 10 обратного нет

По модулю 7 обратим каждый ненулевой остаток: семь - простое, и общих делителей с ним ни у кого нет. По модулю 12 обратимы четыре остатка из одиннадцати. Поэтому там, где нужно делить, модуль берут простым: арифметика по простому модулю умеет все четыре действия.

Что ломается без этого

Первое: отрицательный коэффициент. Алгоритм выдаёт −17, а не 23. Без приведения % m это число уходит дальше, и в языке, где остаток от отрицательного отрицателен, ломает следующую формулу.

Второе: обратный, которого нет. Функция, не проверяющая НОД, вернёт для пары (6, 9) число 8 - коэффициент при шестёрке, приведённый по модулю. 6 · 8 = 48 ≡ 3, а не 1. Ошибки нет, ответ есть, ответ неверный.

Третье: деление остатков напрямую. (a / b) mod m нельзя считать как (a mod m) // (b mod m). 10 / 5 = 2, а по модулю 7 остатки 3 и 5, и 3 // 5 = 0. Правильно: 3 · 5⁻¹ = 3 · 3 = 9 ≡ 2.

Четвёртое: знаменатель, кратный модулю. Число сочетаний по модулю p через обратные работает, пока в знаменателе нет множителя p. При n ≥ p он появляется, и формула молча делит на ноль.

Зачем это в работе

В Python обратный встроен: pow(a, -1, m) с версии 3.8; на тренажёре она тоже есть. Если обратного нет, функция завершается ошибкой, а не возвращает мусор.

Ключ RSA. Открытая часть ключа - число e, секретная - d, обратное к e по секретному модулю. Вся генерация секретного ключа - один вызов расширенного Евклида; глава про RSA это покажет.

Комбинаторика по модулю: число сочетаний считают как произведение числителя на обратные к множителям знаменателя. Так решается беда из урока про остатки - «делить по модулю нельзя».

Уравнения в целых числах. «Можно ли набрать сумму 100 монетами по 6 и по 9» - вопрос о том, делится ли 100 на НОД(6, 9) = 3. Не делится - и перебирать незачем.

Теперь сам

  1. Найди обратный к 5 по модулю 17 расширенным алгоритмом: заполни таблицу, как в механизме.
  2. Есть ли обратный у 4 по модулю 10? У 3 по модулю 10?
  3. Реши 3 · x ≡ 2 (mod 7), пользуясь таблицей обратных по модулю 7.
  4. Сколько решений по модулю 12 у сравнения 8 · x ≡ 4 (mod 12)?

Ответ. 1. Числа 17 и 5. Строки: 17 с парой (1, 0); 5 с парой (0, 1); 17 = 3 · 5 + 2, число 2 с парой (1, −3); 5 = 2 · 2 + 1, число 1 с парой (0, 1) − 2 · (1, −3) = (−2, 7). Итог: −2 · 17 + 7 · 5 = 1. Обратный к 5 - это 7: 5 · 7 = 35 = 2 · 17 + 1.

  1. У 4 нет: НОД(4, 10) = 2. У 3 есть: это 7, 3 · 7 = 21.

  2. Обратный к 3 - это 5. x ≡ 2 · 5 = 10 ≡ 3. Проверка: 3 · 3 = 9 ≡ 2.

  3. НОД(8, 12) = 4, и 4 делится на 4 - решений четыре. После деления на 4: 2 · x ≡ 1 (mod 3), то есть x ≡ 2 (mod 3); по модулю 12 это 2, 5, 8 и 11.

Главное

Деление по модулю - это умножение на обратный элемент, а обратный элемент - побочный продукт алгоритма Евклида, который вместе с остатками ведёт их запись через исходные числа. Существует обратный ровно у тех чисел, что взаимно просты с модулем; по простому модулю - у всех ненулевых. Так арифметика остатков получает четвёртое действие, и цена его - несколько кругов на цифру.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

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