Как рассчитать модуль больших чисел?

Как рассчитать модуль модуля 5 ^ 55 без использования калькулятора?

Я предполагаю, что в теории криптографии есть несколько простых принципов для вычисления таких вещей.

Ответ 1

Хорошо, поэтому вы хотите рассчитать a^b mod m. Сначала мы возьмем наивный подход, а затем посмотрим, как мы можем его доработать.

Сначала уменьшите a mod m. Это означает, что найдем число a1, чтобы 0 <= a1 < m и a = a1 mod m. Затем несколько раз в цикле умножайтесь на a1 и снова уменьшайте mod m. Таким образом, в псевдокоде:

a1 = a reduced mod m
p = 1
for(int i = 1; i <= b; i++) {
    p *= a1
    p = p reduced mod m
}

Таким образом, мы избегаем чисел, больших m^2. Это ключ. Причина, по которой мы избегаем чисел, больших m^2, заключается в том, что на каждом шаге 0 <= p < m и 0 <= a1 < m.

В качестве примера давайте вычислим 5^55 mod 221. Во-первых, 5 уже сокращен mod 221.

  • 1 * 5 = 5 mod 221
  • 5 * 5 = 25 mod 221
  • 25 * 5 = 125 mod 221
  • 125 * 5 = 183 mod 221
  • 183 * 5 = 31 mod 221
  • 31 * 5 = 155 mod 221
  • 155 * 5 = 112 mod 221
  • 112 * 5 = 118 mod 221
  • 118 * 5 = 148 mod 221
  • 148 * 5 = 77 mod 221
  • 77 * 5 = 164 mod 221
  • 164 * 5 = 157 mod 221
  • 157 * 5 = 122 mod 221
  • 122 * 5 = 168 mod 221
  • 168 * 5 = 177 mod 221
  • 177 * 5 = 1 mod 221
  • 1 * 5 = 5 mod 221
  • 5 * 5 = 25 mod 221
  • 25 * 5 = 125 mod 221
  • 125 * 5 = 183 mod 221
  • 183 * 5 = 31 mod 221
  • 31 * 5 = 155 mod 221
  • 155 * 5 = 112 mod 221
  • 112 * 5 = 118 mod 221
  • 118 * 5 = 148 mod 221
  • 148 * 5 = 77 mod 221
  • 77 * 5 = 164 mod 221
  • 164 * 5 = 157 mod 221
  • 157 * 5 = 122 mod 221
  • 122 * 5 = 168 mod 221
  • 168 * 5 = 177 mod 221
  • 177 * 5 = 1 mod 221
  • 1 * 5 = 5 mod 221
  • 5 * 5 = 25 mod 221
  • 25 * 5 = 125 mod 221
  • 125 * 5 = 183 mod 221
  • 183 * 5 = 31 mod 221
  • 31 * 5 = 155 mod 221
  • 155 * 5 = 112 mod 221
  • 112 * 5 = 118 mod 221
  • 118 * 5 = 148 mod 221
  • 148 * 5 = 77 mod 221
  • 77 * 5 = 164 mod 221
  • 164 * 5 = 157 mod 221
  • 157 * 5 = 122 mod 221
  • 122 * 5 = 168 mod 221
  • 168 * 5 = 177 mod 221
  • 177 * 5 = 1 mod 221
  • 1 * 5 = 5 mod 221
  • 5 * 5 = 25 mod 221
  • 25 * 5 = 125 mod 221
  • 125 * 5 = 183 mod 221
  • 183 * 5 = 31 mod 221
  • 31 * 5 = 155 mod 221
  • 155 * 5 = 112 mod 221

Следовательно, 5^55 = 112 mod 221.

Теперь мы можем улучшить это, используя возведение в степень путем возведения в квадрат; это известный трюк, в котором мы уменьшаем степень возведения в степень, требуя только log b умножений вместо b. Обратите внимание, что с описанным выше алгоритмом, возведение в степень путем возведения в квадрат улучшения, вы получаете двоичный метод справа налево.

a1 = a reduced mod m
p = 1
while (b > 0) {
     if (b is odd) {
         p *= a1
         p = p reduced mod m
     }
     b /= 2
     a1 = (a1 * a1) reduced mod m
}

Таким образом, поскольку 55 = 110111 в двоичном

  • 1 * (5^1 mod 221) = 5 mod 221
  • 5 * (5^2 mod 221) = 125 mod 221
  • 125 * (5^4 mod 221) = 112 mod 221
  • 112 * (5^16 mod 221) = 112 mod 221
  • 112 * (5^32 mod 221) = 112 mod 221

Поэтому ответ 5^55 = 112 mod 221. Причина этого в том, что

55 = 1 + 2 + 4 + 16 + 32

так что

5^55 = 5^(1 + 2 + 4 + 16 + 32) mod 221
     = 5^1 * 5^2 * 5^4 * 5^16 * 5^32 mod 221
     = 5 * 25 * 183 * 1 * 1 mod 221
     = 22875 mod 221
     = 112 mod 221

На шаге, где мы вычисляем 5^1 mod 221, 5^2 mod 221 и т.д., заметим, что 5^(2^k)= 5^(2^(k-1)) * 5^(2^(k-1)), поскольку 2^k = 2^(k-1) + 2^(k-1), чтобы мы могли сначала вычислить 5^1 и уменьшить mod 221, тогда квадрат это и уменьшить mod 221, чтобы получить 5^2 mod 221 и т.д.

Вышеупомянутый алгоритм формализует эту идею.

Ответ 2

Чтобы добавить к Джейсону ответ:

Вы можете ускорить процесс (что может быть полезно для очень больших показателей), используя двоичное расширение экспоненты. Сначала вычислите 5, 5 ^ 2, 5 ^ 4, 5 ^ 8 mod 221 - вы делаете это путем повторного квадратирования:

 5^1 = 5(mod 221)
 5^2 = 5^2 (mod 221) = 25(mod 221)
 5^4 = (5^2)^2 = 25^2(mod 221) = 625 (mod 221) = 183(mod221)
 5^8 = (5^4)^2 = 183^2(mod 221) = 33489 (mod 221) = 118(mod 221)
5^16 = (5^8)^2 = 118^2(mod 221) = 13924 (mod 221) = 1(mod 221)
5^32 = (5^16)^2 = 1^2(mod 221) = 1(mod 221)

Теперь мы можем написать

55 = 1 + 2 + 4 + 16 + 32

so 5^55 = 5^1 * 5^2 * 5^4 * 5^16 * 5^32 
        = 5   * 25  * 625 * 1    * 1 (mod 221)
        = 125 * 625 (mod 221)
        = 125 * 183 (mod 183) - because 625 = 183 (mod 221)
        = 22875 ( mod 221)
        = 112 (mod 221)

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

Ответ 3

/* The algorithm is from the book "Discrete Mathematics and Its
   Applications 5th Edition" by Kenneth H. Rosen.
   (base^exp)%mod
*/

int modular(int base, unsigned int exp, unsigned int mod)
{
    int x = 1;
    int power = base % mod;

    for (int i = 0; i < sizeof(int) * 8; i++) {
        int least_sig_bit = 0x00000001 & (exp >> i);
        if (least_sig_bit)
            x = (x * power) % mod;
        power = (power * power) % mod;
    }

    return x;
}

Ответ 4

5^55 mod221

= (   5^10         * 5^10         * 5^10         * 5^10          * 5^10          * 5^5) mod221    

= ( ( 5^10) mod221 * 5^10         * 5^10         * 5^10          * 5^10          * 5^5) mod221 

= (   77           * 5^10         * 5^10         * 5^10          * 5^10          * 5^5) mod221   

= ( ( 77           * 5^10) mod221 * 5^10         * 5^10          * 5^10          * 5^5) mod221 

= (   183                         * 5^10         * 5^10          * 5^10          * 5^5) mod221 

= ( ( 183                         * 5^10) mod221 * 5^10          * 5^10          * 5^5) mod221 

= (   168                                        * 5^10          * 5^10          * 5^5) mod221 

= ( ( 168                                        * 5^10) mod 221 * 5^10          * 5^5) mod221 

= (   118                                                        * 5^10          * 5^5) mod221 

= ( ( 118                                                        * 5^10) mod 221 * 5^5) mod221 

= (   25                                                                         * 5^5) mod221 

=     112

Ответ 5

Китайская теорема о остатках приходит в голову как начальная точка как 221 = 13 * 17. Итак, сложите это на две части, которые получаются в конце концов, один для мод 13 и один для мод 17. Во-вторых, я считаю, что существует некоторое доказательство того, что a (p-1) = 1 mod p для всех ненулевых а, что также помогает уменьшить вашу проблему как 5 ^ 55 составляет 5 ^ 3 для случая мод 13 при 13 * 4 = 52. Если вы посмотрите на тему "Конечные поля", вы можете найти некоторые хорошие результаты о том, как решить эту проблему.

EDIT: причина, по которой я упоминаю факторы, заключается в том, что это создает способ превратить нуль в ненулевые элементы, как если бы вы пробовали что-то вроде 13 ^ 2 * 17 ^ 4 mod 221, ответ равен нулю с 13 * 17 = 221. Множество больших чисел не будет простым, хотя есть способы найти большие простые числа, поскольку они много используются в криптографии и других областях в математике.

Ответ 6

То, что вы ищете, - это модульное возведение в степень, в частности модульное двоичное возведение в степень. Этот ссылка wikipedia имеет псевдокод.

Ответ 7

Это часть кода, который я сделал для проверки IBAN. Не стесняйтесь использовать.

    static void Main(string[] args)
    {
        int modulo = 97;
        string input = Reverse("100020778788920323232343433");
        int result = 0;
        int lastRowValue = 1;

        for (int i = 0; i < input.Length; i++)
        {
            // Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number                                                                        
            if (i > 0)
            {
                lastRowValue = ModuloByDigits(lastRowValue, modulo);
            }
            result += lastRowValue * int.Parse(input[i].ToString());
        }
        result = result % modulo;
        Console.WriteLine(string.Format("Result: {0}", result));            
    }

    public static int ModuloByDigits(int previousValue, int modulo)
    {
        // Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number                        
        return ((previousValue * 10) % modulo);
    }
    public static string Reverse(string input)
    {
        char[] arr = input.ToCharArray();
        Array.Reverse(arr);
        return new string(arr);
    }

Ответ 8

Ответ Джейсона на Java (примечание i < exp).

private static void testModulus() {
    int bse = 5, exp = 55, mod = 221;

    int a1 = bse % mod;
    int p = 1;

    System.out.println("1. " + (p % mod) + " * " + bse + " = " + (p % mod) * bse + " mod " + mod);

    for (int i = 1; i < exp; i++) {
        p *= a1;
        System.out.println((i + 1) + ". " + (p % mod) + " * " + bse + " = " + ((p % mod) * bse) % mod + " mod " + mod);
        p = (p % mod);
    }

}

Ответ 9

Это называется модулярным возведением в степень (https://en.wikipedia.org/wiki/Modular_exponentiation).

Скажем, у вас есть следующее выражение:

19^3 mod 7

Вместо прямого включения 19 вы можете сделать следующее:

(((19 mod 7) * 19) mod 7) * 19) mod 7

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

x mod N -> x ^ 2 mod N -> x ^ 4 mod -> ... x ^ 2 |log y| mod N

Модульный алгоритм возведения в степень делает предположения, что:

x ^ y == (x ^ |y/2|) ^ 2 if y is even
x ^ y == x * ((x ^ |y/2|) ^ 2) if y is odd

И поэтому рекурсивный модульный алгоритм возведения в степень будет выглядеть так: java:

public static long modExp(long x, long y, long N) {
    if(y == 0)
        return 1;

    long z = modExp(x, Math.abs(y/2), N);

    if(y % 2 == 0)
        return (long) ((Math.pow(z, 2)) % N);
    return (long) ((x * Math.pow(z, 2)) % N);
}

Ответ 10

Просто предоставите другую реализацию ответа Джейсона на C.

После обсуждения с моими одноклассниками, основанными на объяснении Джейсона, мне больше нравится рекурсивная версия, если вы не очень заботитесь о производительности:

Например:

#include<stdio.h>

int mypow( int base, int pow, int mod ){
    if( pow == 0 ) return 1;
    if( pow % 2 == 0 ){
        int tmp = mypow( base, pow >> 1, mod );
        return tmp * tmp % mod;
    }
    else{
        return base * mypow( base, pow - 1, mod ) % mod;
    }
}

int main(){
    printf("%d", mypow(5,55,221));
    return 0;
}