web-dev-qa-db-fra.com

Comment calculer le module de grands nombres?

Comment calculer le module de 5 ^ 55 module 221 sans utiliser beaucoup de calculatrice?

Je suppose qu'il existe des principes simples dans la théorie des nombres en cryptographie pour calculer de telles choses.

64
Priyank Bolia

Bon, vous voulez donc calculer a^b mod m. Nous allons d'abord adopter une approche naïve et ensuite voir comment nous pouvons l'affiner.

Tout d'abord, réduisez a mod m. Cela signifie que vous devez trouver un numéro a1 pour que 0 <= a1 < m et a = a1 mod m. Puis à plusieurs reprises dans une boucle, multipliez par a1 et réduisez à nouveau mod m. Ainsi, en pseudocode:

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

Ainsi, nous évitons les nombres supérieurs à m^2. Ceci est la clé. Nous évitons les nombres plus grands que m^2 parce que _ à chaque étape 0 <= p < m et 0 <= a1 < m.

Par exemple, calculons 5^55 mod 221. Tout d'abord, 5 est déjà réduit mod 221.

  1. 1 * 5 = 5 mod 221
  2. 5 * 5 = 25 mod 221
  3. 25 * 5 = 125 mod 221
  4. 125 * 5 = 183 mod 221
  5. 183 * 5 = 31 mod 221
  6. 31 * 5 = 155 mod 221
  7. 155 * 5 = 112 mod 221
  8. 112 * 5 = 118 mod 221
  9. 118 * 5 = 148 mod 221
  10. 148 * 5 = 77 mod 221
  11. 77 * 5 = 164 mod 221
  12. 164 * 5 = 157 mod 221
  13. 157 * 5 = 122 mod 221
  14. 122 * 5 = 168 mod 221
  15. 168 * 5 = 177 mod 221
  16. 177 * 5 = 1 mod 221
  17. 1 * 5 = 5 mod 221
  18. 5 * 5 = 25 mod 221
  19. 25 * 5 = 125 mod 221
  20. 125 * 5 = 183 mod 221
  21. 183 * 5 = 31 mod 221
  22. 31 * 5 = 155 mod 221
  23. 155 * 5 = 112 mod 221
  24. 112 * 5 = 118 mod 221
  25. 118 * 5 = 148 mod 221
  26. 148 * 5 = 77 mod 221
  27. 77 * 5 = 164 mod 221
  28. 164 * 5 = 157 mod 221
  29. 157 * 5 = 122 mod 221
  30. 122 * 5 = 168 mod 221
  31. 168 * 5 = 177 mod 221
  32. 177 * 5 = 1 mod 221
  33. 1 * 5 = 5 mod 221
  34. 5 * 5 = 25 mod 221
  35. 25 * 5 = 125 mod 221
  36. 125 * 5 = 183 mod 221
  37. 183 * 5 = 31 mod 221
  38. 31 * 5 = 155 mod 221
  39. 155 * 5 = 112 mod 221
  40. 112 * 5 = 118 mod 221
  41. 118 * 5 = 148 mod 221
  42. 148 * 5 = 77 mod 221
  43. 77 * 5 = 164 mod 221
  44. 164 * 5 = 157 mod 221
  45. 157 * 5 = 122 mod 221
  46. 122 * 5 = 168 mod 221
  47. 168 * 5 = 177 mod 221
  48. 177 * 5 = 1 mod 221
  49. 1 * 5 = 5 mod 221
  50. 5 * 5 = 25 mod 221
  51. 25 * 5 = 125 mod 221
  52. 125 * 5 = 183 mod 221
  53. 183 * 5 = 31 mod 221
  54. 31 * 5 = 155 mod 221
  55. 155 * 5 = 112 mod 221

Par conséquent, 5^55 = 112 mod 221.

Maintenant, nous pouvons améliorer cela en utilisant exponentiation par quadrature ; C’est le fameux truc dans lequel nous réduisons l’exponentiation à la nécessité de ne multiplier que par log b multiplications au lieu de b. Notez qu'avec l'algorithme que j'ai décrit ci-dessus, l'exponentiation par amélioration au carré, vous vous retrouvez avec le méthode binaire de droite à gauche .

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
}

Ainsi, depuis 55 = 110111 en binaire

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

Par conséquent, la réponse est 5^55 = 112 mod 221. Cela fonctionne parce que

55 = 1 + 2 + 4 + 16 + 32

pour que

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

Dans l'étape où nous calculons 5^1 mod 221, 5^2 mod 221, etc., nous notons que 5^(2^k) = 5^(2^(k-1)) * 5^(2^(k-1)) car 2^k = 2^(k-1) + 2^(k-1) afin que nous puissions tout d'abord calculer 5^1 et réduire mod 221, puis cocher ceci et réduisez mod 221 pour obtenir 5^2 mod 221, etc.

L'algorithme ci-dessus formalise cette idée.

93
jason

Pour ajouter à la réponse de Jason:

Vous pouvez accélérer le processus (ce qui peut être utile pour les très grands exposants) en utilisant le développement binaire de l'exposant. Calculez d’abord 5, 5, 2, 5, 4, 5, 8 mod 221 - vous le faites en répétant des quadratures:

 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)

Maintenant nous pouvons écrire

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)

Vous pouvez voir comment, pour de très grands exposants, ce sera beaucoup plus rapide (je crois que c'est log par opposition à linéaire en b, mais pas certain)

27
Tom Smith
/* 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;
}
12
Timothy Kwok
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
3
Udhayakumar.c

Cela fait partie du code que j'ai créé pour la validation IBAN. N'hésitez pas à utiliser.

    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);
    }
2
Jaroslav Kubacek

Théorème du reste chinois vient à l’esprit comme point initial comme 221 = 13 * 17. Donc, divisez cela en 2 parties qui se combinent à la fin, une pour le mod 13 et une pour le mod 17. Deuxièmement, je crois il existe des preuves de ^ (p-1) = 1 mod p pour tout non a nul, ce qui permet également de réduire votre problème, car 5 ^ 55 devient 5 ^ 3 pour le cas mod 13 et 13 * 4 = 52. Si vous examinez le sujet "Champs finis", vous obtiendrez peut-être de bons résultats pour résoudre ce problème.

EDIT: La raison pour laquelle je mentionne les facteurs est que cela crée un moyen de factoriser zéro en éléments non nuls, comme si vous essayiez quelque chose comme 13 ^ 2 * 17 ^ 4 mod 221, la réponse est zéro puisque 13 * 17 = 221. Un grand nombre de grands nombres ne seront pas des nombres premiers, bien qu'il existe des moyens de trouver des nombres premiers de grande taille, car ils sont beaucoup utilisés en cryptographie et dans d'autres domaines de la mathématique.

2
JB King

Ce que vous recherchez, c'est une exponentiation modulaire, en particulier une exponentiation binaire modulaire. Ce lien wikipedia a un pseudocode.

2
job

La réponse de Jason en Java (note 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);
    }

}
1
Martin Pfeffer

Cela s'appelle une exponentiation modulaire ( https://en.wikipedia.org/wiki/Modular_exponentiation ). 

Supposons que vous avez l'expression suivante:

19 ^ 3 mod 7

Au lieu d’alimenter directement 19, vous pouvez effectuer les opérations suivantes:

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

Mais cela peut aussi prendre beaucoup de temps en raison de nombreuses multipliations séquentielles et vous pouvez donc multiplier sur des valeurs au carré:

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

L’algorithme d’exponentiation modulaire suppose que:

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

Ainsi, l'algorithme d'exponentiation modulaire récursif ressemblera à ceci en Java:

/**
* Modular exponentiation algorithm
* @param x Assumption: x >= 0
* @param y Assumption: y >= 0
* @param N Assumption: N > 0
* @return x ^ y mod N
*/
public static long modExp(long x, long y, long N) {
    if(y == 0)
        return 1 % N;

    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);
}

Un merci spécial à @chux pour l'erreur trouvée avec une valeur de retour incorrecte en cas de comparaison entre y et 0. 

1
Stepan Pogosyan

Il suffit de fournir une autre implémentation de la réponse de Jason par C.

Après avoir discuté avec mes camarades de classe, à partir des explications de Jason, j'aime mieux la version récursive si vous vous souciez peu de la performance:

Par exemple:

#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;
}
0
Boris