Chapitre 5 Chapitre 5. Exponentiation modulaire Il est fréquent qu en arithmétique on soit amené à déterminer le reste de la division de a y par n, où a, y et n sont des entiers naturels (pensons par exemple au théorème de Fermat ). C est, en termes savants, le problème de l exponentiation modulaire. Or l utilisation directe de la fonction mod de la TI-Nspire présente quelques petites lacunes lacunes que nous pourrons facilement corriger par programmation. Sommaire Chapitre 5. Exponentiation modulaire... 65 1. Introduction : un problème de calcul... 66 2. Vers un algorithme performant... 67 2.1 Les calculs de proche en proche... 67 2.2 L algorithme sur le tableur... 69 2.3 Une première fonction... 70 2.4 Un doigt de récursivité... 71 Christian Vassard (IUFM Rouen)
66 Mathématiques et TI-Nspire 1. Introduction : un problème de calcul Intéressons-nous au calcul du reste dans la division de 10 n par 7 : la fonction mod semble évidemment tout indiquée pour un tel calcul. Ainsi, on constate que le calcul de mod(10 n,7) se fait sans aucun problème jusqu à n = 992. En revanche, pour des exposants de 10 compris entre 993 et 999, la calculatrice renvoie 0 (suivi du point décimal pour indiquer qu elle est passée en mode approché) et au delà de 10 1000, elle renvoie mod(,7). Il est clair que la calculatrice effectue en premier le calcul de la puissance. Tout le problème est finalement de savoir si le calcul de cette puissance est exact ou approché. Or, comme le laisse voir l écran ci-dessous, la TI-Nspire travaille en arithmétique exacte pour des nombres entiers possédant jusqu à 993 chiffres 1 ; pour des entiers n vérifiant 10 993 n < 10 1000, elle passe en écriture scientifique ; au delà, le nombre est considéré comme égal à l infini. Faut-il pour autant renoncer à tout calcul exact, d autant que le résultat de mod(10 1000,7) est banalement un entier compris entre 0 et 6? S en priver serait en tout cas regrettable, car l exponentiation modulaire intervient dans de nombreuses situations en arithmétique (pensons par exemple au théorème de Fermat ou au théorème d Euler, à la cryptographie,...). Nous nous proposons donc, dans la suite, de mettre au point un algorithme efficace d exponentiation modulaire, nous permettant de venir à bout des calculs précédents. 1 C était 615 chiffres pour une voyage 200!
Exponentiation modulaire 67 2. Vers un algorithme performant 2.1 Les calculs de proche en proche Comment donc résoudre le problème précédent? L idée la plus immédiate serait de faire les calculs de proche en proche, jusqu à obtenir le résultat demandé. Par exemple, pour obtenir 5 1063 modulo 2159, on peut faire les calculs suivants : mod(5,2159) = 5 ; mod(5 2,2159) = 25 ; mod(5 3,2159) = 25 5 = 125 ; mod(5 4,2159) = 125 5 = 625 ; mod(5 5,2159) = 966, qui est le reste dans la division de 625 5 = 3125 par 2159 ; etc. Mais cet algorithme, qui permet à coup sûr d arriver au résultat (on se ramène toujours à des entiers naturels inférieurs à 2159), est glouton en temps, à cause des 1062 étapes intermédiaires qu il demande. Autant dire que pour des exposants plus élevés, le calcul ne pourra pas être mené à son terme Tout réside donc dans un calcul efficace de ces produits successifs. Or on peut faire mieux et plus rapidement, à moindre frais. Prenons un exemple simple, sans se préoccuper pour le moment de mod. Pour calculer a 128, il est maladroit d effectuer les 127 produits successifs qui définissent la puissance. Pour avoir le résultat, il vaut beaucoup mieux procéder ainsi : calcul de a 2, puis de a 4, a 8, a 16, a 32, a 64 et enfin a 128, ce qui ne demandera que 7 élévations au carré successives. Mais si l exposant n est pas une puissance de 2? Prenons par exemple a 96 : à défaut d être lui-même une puissance de 2, 96 s écrit comme somme de deux puissances de 2 : 96 = 64 +32. Par suite, a 96 = a 64 a 32, dont le calcul résulte des élévations au carré obtenues plus haut. La méthode peut toujours être mise en œuvre : car écrire un nombre sous la forme d une somme de puissances de 2 revient à décomposer ce nombre dans la base 2 Examinons par exemple ce que l on obtiendrait pour notre exposant 1063. Procédons par étapes. Étape 1 : on décompose 1063 en base 2, en procédant à des divisions successives par 2. 1063 2 1 531 2 1 265 2 1 132 2 0 66 2 0 33 2 1 16 2 0 8 2 0 4 2 0 2 2 0 1 2 1 0
68 Mathématiques et TI-Nspire On sait que le premier reste correspond au chiffre des unités, le second des «deuzaines» 2 et ainsi de suite. Autrement dit le nombre s écrit en partant des derniers restes obtenus soit 1063 = 10000100111 d où l on déduit la décomposition de 1063 en somme de puissances de 2 : 1063 = 2 10 + 2 5 + 2 2 + 2 1 + 2 0 = 1024 + 32 + 4 + 2 + 1. Étape 2 : par suite, d après les propriétés des puissances, on peut écrire : a 1063 = 1 2 4 32 1024 a = a a 2 a 4 a 32 a 1024. Étape 3 : on procède ensuite à des élévations au carré successives à partir de a : a, a 2, a 4, a 8, a 16, a 32, a 64, a 128, a 256, a 512, a 1024 Nous intéressent uniquement ceux qui sont entourés, qui permettent d obtenir a 1063. Remarquons qu ils correspondent en fait à des restes égaux à 1 dans les divisions précédentes Il suffit de faire le produit de ces entiers, éventuellement modulo un autre entier, pour avoir le résultat cherché Bilan : comme précédemment, on constate qu on a beaucoup moins d opérations à effectuer que les 1062 de la première méthode! En fait, 11 divisions par 2 et 10 élévations au carré successives et 4 multiplications suffiront à donner le résultat. Le gain est appréciable, et on peut s attendre à ce que l algorithme soit particulièrement efficace! En reprenant le calcul de 5 1063 modulo 2159, la démarche précédente conduit à 3 : restes dans les divisions par 2 élévations au carré successives carrés modulo n = 2159 z modulo 2159 1 (unité) 5 5 5 1 (deuzaine) 5 2 25 mod(5 25,2159)=125 1 (etc.) 5 4 625 mod(125 625,2159)=401 0 5 8 2005 0 5 16 2126 1 5 32 1089 mod(401 1089,2159)=571 0 5 64 630 0 5 128 1803 0 5 256 1514 0 5 512 1497 1 5 1024 2126 mod(571 2126,2159)=588 On peut en conclure que mod(5 1063,2159)=588 : nous avons par cette méthode mené le calcul à son terme. 2 Un peu comme dix donne dizaine 3 Les variables a et z utilisées ici correspondent à celles du programme qui suit.
Exponentiation modulaire 69 Le tableau, tel qu il est présenté, résume la méthode employée : on calcule les carrés successifs de 5 modulo 2159, et on ne cumule dans z (multiplicativement d une part et modulo 2159 d autre part) que les valeurs correspondant à un reste égal à 1. Le nombre de multiplications, effectuées modulo 2159 pour que les calculs n explosent pas, est donc singulièrement diminué. On obtient finalement 588, ce que le calcul confirme : La méthode s appliquerait sans plus de difficulté à un nombre plus grand, 9 1063 par exemple, pour lequel l utilisation bête et brutale de mod donnerait 0 ( car 9 1063 dépasse 10 1000 ). 2.2 L algorithme sur le tableur La présentation du paragraphe précédent suggère d employer le tableur pour automatiser les calculs : c est un premier pas vers la mise en œuvre effective de l algorithme. Quelques remarques. Tout d abord, le nombre est mémorisé dans une variable a, l exposant dans une variable y et l entier du modulo dans une variable n. Dans la colonne C, on calcule les quotients des divisions successives par 2 : on saisit int(c2/2) dans la cellule C3 et on recopie sur quelques lignes. La colonne D est consacrée au reste : dans D3, on tape =mod(c2,2). Dans la cellule E3, on saisit =a puis dans E4, =mod(e3 2,n) ; on recopie sur le même nombre de lignes.
70 Mathématiques et TI-Nspire Enfin, dans F2, on met =1, puis dans F3, =when(d3=1,mod(d2. e3,n),d2,void) : on n effectue la multiplication modulo n que dans le cas où le reste est égal à 1, sinon on ne fait rien. Le résultat est lu en face du premier 0 dans la suite des quotients, ou encore du dernier reste égal à 1 dans la colonne D : ici on peut écrire que mod(9 1063,2159) = 1685. 2.3 Une première fonction Passons à l écriture d une fonction, avec les idées exposées précédemment. Nous l avons appelée puismod, avec trois paramètres en entrée, a, y et n : elle permet le calcul du reste dans la division par n de a y. puismod(a,y,n) = reste dans la division de a y par n La fonction est conditionnée par une boucle While, gérée par la variable y, qui mémorise les quotients successifs dans la division par 2 : en effet, on ne sait pas a priori combien de fois on va parcourir cette boucle. On en sort par contre dès que le quotient est nul, ce qui signifie que la décomposition en base 2 de l exposant est terminée. À chaque passage dans la boucle, on calcule, modulo n, le carré de a et on met à jour la nouvelle valeur de y. On mène parallèlement la décomposition de l exposant y en base 2 et le calcul demandé, stocké dans la variable z. Si le reste dans la division par 2 vaut 1, le carré de a doit être cumulé multiplicativement dans la variable z ; sinon, il n y a rien à faire. Le code est proposé ci-après. La fonction puismod est très efficace et les réponses sont renvoyées en un temps très court ; au contraire de mod, elle autorise des calculs avec des exposants relativement grands. Le dernier résultat renvoyé, 0., est incorrect car on est passé en mode approché (remarquer le point qui suit la réponse) : mais il met en jeu des nombres qu on peut qualifier de gigantesques pour une calculatrice
Exponentiation modulaire 71 2.4 Un doigt de récursivité Une autre piste consiste à utiliser la récursivité, comme nous l avons déjà fait pour le calcul du pgcd, avec l avantage d une écriture relativement simple et naturelle. Supposons que l on cherche à calculer a y modulo n. On peut alors écrire : y 2 2 si y est pair, a y modulo n est égal a modulo n ; si y est impair, a y modulo n est égal a a y 1 2 2 modulo n. On peut en déduire l écriture d une fonction récursive. L exposant y est amené ainsi à avoir des valeurs de plus en plus petites, par divisions par 2 successives. Il finira par valoir 1, et dans ce cas, on sait que la valeur à retourner est a. Les résultats sont obtenus assez rapidement mais restent décevants : lorsque a y dépasse les capacités de la machine, le calcul ne peut plus être effectué. Rien de mieux donc que la fonction mod : Essayons de comprendre pourquoi en examinant comment le calcul se fait à partir par exemple de expmod(2,30,10) : 30 est pair, donc le premier appel renvoie mod(expmod(2 2,15,10),10) ; l instruction précédente engendre un appel de la fonction expmod qui renvoie, puisque 15 est impair et distinct de 1, 2 2. mod(expmod(2 4,7,10),10) ;
72 Mathématiques et TI-Nspire encore un appel de la fonction expmod qui renvoie, puisque 7 est impair et distinct de 1, 2 4. mod(expmod(2 8,3,10),10) ; encore un appel de la fonction expmod qui renvoie, puisque 3 est impair et distinct de 1, 2 8. mod(expmod(2 16,1,10),10) ; cette fois, l exposant vaut 1 et la fonction renvoie 2 16. Bilan : la suite des appels récursifs de notre fonction conduit à estimer : mod(2 2. mod(2 4. mod(2 8. mod(expmod(2 16,1,10),10),10),10),10). Ici, l évaluation de 2 16 n entraîne pas de dépassement de capacité, mais on conçoit aisément que le même type de problème qu avec mod peut survenir assez rapidement. Mais cette fois-ci, on peut contrôler dans la fonction la taille des nombres renvoyés : il suffit de ramener chaque calcul à son reste modulo n en utilisant le plus souvent possible la fonction mod. On obtient alors la fonction récursive suivante : Les résultats sont alors satisfaisants, mais si de trop nombreux appels récursifs à la fonction exmod sont effectués, on risque de saturer la mémoire de la calculatrice, ou de l ordinateur Pour cette raison, notre fonction puismod précédente 4, qui n a pas ce défaut, doit être préférée à celle-ci : 4 Il existe aussi une fonction pwrmod dans la bibliothèque numtheory qui remplit le même rôle que notre puismod et qui possède la même syntaxe. Au demeurant, ce n est pas parce que les fonctions pré-écrites existent déjà qu il faut se dispenser de réfléchir sur les algorithmes en œuvre. Ce que nous avons fait dans ce chapitre