M1 MFA année 2013–2014. Algorithmique : notes de cours

publicité
M1 MFA année 2013–2014. Algorithmique : notes de cours
Version du 8 décembre 2013
Programme. Notion d’algorithme, complexité d’un algorithme. Notation dite de Landau :
O, Ω, Θ. Rappels sur la comparaison des fonctions.
Algorithmes de tri : tri par insertion, tri rapide.
Opérations arithmétiques de base sur les entiers : addition, soustraction, multiplication, exponentiation, division euclidienne avec reste.
Algorithmes arithmétiques : calcul du pgcd, algorithme d’Euclide étendu, Bézout, utilisation
du théorème chinois.
FFT, multiplication rapide.
Opérations sur les polynômes (en principe en une variable), algorithme d’Euclide, calcul du
pgcd, théorème chinois, multiplication rapide.
Algèbre linéaire : solution d’un système d’équation linéaires, calcul d’un déterminant, . . ..
Racines d’un polynôme à coefficients réels et complexes : localisation, séparation, approximation.
Public visé : agrégation de mathématiques (option C calcul formel, éventuellement utile pour
option D info) et math-info (surtout algorithmique en théorie des nombres et cryptologie).
Quelques références : Pierre Damphouse : Petite introduction à l’algorithmique, Ellipses
(2005). Maurice Mignotte : Mathématiques pour le calcul formel, PUF (1988). Maurice Mignotte :
Algèbre concrète, Ellipses, (2003). Joachim von zur Gathen, Jürgen Gerhard : Modern computer
algebra, Cambridge University Press, deuxième édition (2003). Donald E. Knuth : The art of
computer programming, (4 volumes), Addison Wesley, plusieurs éditions (plus avancé).
Notion d’algorithme. Je ne donnerai pas de définition précise. Il s’agit d’une série d’instructions faisant intervenant des opérations simples , dites élémentaires.
Sauf indication contraire, les algorithmes sont déterministes, c’est-à-dire, le résultat de
chaque opération est uniquement déterminée. Il y a aussi des algorithmes probabilistes, où
les opérations font intervenir un choix au hasard (par exemple un entier choisi au hasard). Une
autre forme d’algorithme qui font intervenir une hypothèse que nous ne savons pas démontrer dans
l’état des connaissances mathématiques actuelles, mais qui, dans la pratique, sont très efficaces.
Un exemple est la recherche du plus petit nombre premier supérieur à un entier n donné. Pour
cela, on utilise la méthode la plus naı̈ve imaginable : on test successivement pour primalité chacun
les entiers n + 1, n + 2, . . .. En pratique, on constate qu’il suffit — en moyenne — de tester environ log n entiers avant de rencontrer un nombre premier, mais nos connaissances mathématiques
actuelles permettent seulement de démontrer qu’il suffit de tester au plus nc entiers, où c > 0 est
une constante qui, il est vrai, diminue avec le temps. Un tel algorithme est appelé un algorithme
heuristique.
Exemples (i ) L’instruction factoriser(n) (où n ≥ 2 un entier naturel) n’est pas un algorithme, car l’instruction de factoriser un entier n’est pas une instruction élémentaire (et il y a
1
en fait plusieurs algorithmes de factorisation d’un entier). Un algorithme de factorisation est
une séquence d’instructions simples (telles addition, multiplication, division, comparaison de deux
entiers) que, si l’on les appliquent à n, fournit la factorisation de n.
(ii ) De même, l’instruction trier(L), où L est une liste de mots (par exemple de la langue
française), n’est pas un algorithme. Ici, instruction simple pourrait signifier interchangement de
deux mots (transposition).
(iii ) On peut objecter que l’addition, la multiplication, . . ., de deux entiers ne sont pas des
opérations élémentaires, mais deviennent de plus en plus complexes avec les grandeurs. C’est vrai.
En réalité, les opérations élémentaires arithmétiques sont l’addition, la multiplication, . . ., de deux
puissances de 2.
Ici, on peut encore objecter qu’un grand entier est plus complexe qu’un petit. Cela est une
question de taille de mémoire, alors que nous nous limiterons à des questions de complexité
d’exécution qui influencer surtout le temps de calcul.
Nous allons donc parfois supposer que l’addition, la multiplication, . . ., peuvent se faire en
temps constant, surtout lorsque les algorithmes ont une complexité beaucoup plus importante que
log n (par ex. une puissance de n).
Parmi des opérations élémentaires, il faut aussi tenir compte du nombre de cas à exécuter dans
un pour ou dans un tantque, le tests élémentaires dans un si, les retourner. Et, bien entendu,
si un programme fait appel à un autre, les instructions exécutées par ce dernier.
Par exemple, dans le pseudoprogramme (pas de langage de programmation dans ce cours) :
pour i de 1 à n
si 2 divise i retourner i/2
sinon retourner i
finsi
finpour
chaque valeur de i utilise un test de parité. Lorsque i est pair il faut le diviser par 2 et il y a donc le
test plus la division plus le retourner à exécuter, ce qui fait 3 opérations élémentaires. Par contre,
lorsque i est impair, il y n’y a que le test et le retourner à exécuter, soit 2 opérations élémentaires.
Le nombre total d’opérations élémentaires est donc n + 3Np (n) + 2Ni (n) (Np (n), Ni (n) le nombre
d’entiers pairs, impairs entre 1 et n).
Ici, j’ai compté le test de parité et la division par 2 comme des opérations élémentaires,
car, sur machine, elle correspond à regarder si le dernier bit de i est nul et à décaler tous les
bits de i un pas à droite. On pourrait objecter, avec raison, que décaler un bit un pas à droite
est une opération élémentaire mais que, comme i est représenté par blog2 ic + 1 bits, la division
nécessite
ce nombre d’opération élémentaires. Le pseudoprogramme nécessiterait alors n+2Np (n)+
P
i pair (blog2 ic + 1) + 2Ni (n) opérations élémentaires.
Remarque. L’algorithmique étudie aussi l’existence ou la non existence d’algorithmes. Un
exemple célèbre est le Théorème de Matijasevich, qui a pour conséquence qu’il n’existe pas
d’algorithme pour décider si oui on non une famille d’équations polynômiales à coefficients entiers
possède une solution en entiers. Dans ce cours, nous serons plutôt intéressés par des problèmes qui
possèdent un algorithme trivial dont l’existence est en générale évidente (par exemple, il suffit
d’effectuer de tests ou d’opérations sur un ensemble fini explicite). Le but est la recherche d’algorithmes plus efficaces, et surtout plus rapide. Un exemple typique est le problème de déterminer
si oui ou non un entier naturel n ≥ 2 donné est un nombre premier. L’algorithme trivial consiste
alors à tester si n est divisible par un entier m tel que 2 ≤ m ≤ n − 1, et un algorithme trivial
consiste donc de tester successivement si 2 divise n, si 3 divise n et ainsi de suite. Ici l’opération de
division n’est pas une opération élémentaire, mais peut être réduite à une séquence d’opérations
2
élémentaires, par exemple en appliquant la division euclidienne avec reste et en constatant si le
reste est nul ou non. Le but est de trouver un algorithme plus rapide.
Complexité, notation de Landau
Dans ce cours, log désigne le logarithme népérien, loga le log en base a, a > 0 étant un réel.
Il y a donc place pour discussion concernant le nombre exact d’opération élémentaires. Mon
point de vue est assez rigoureux ; j’essaie de compter tous qui pourrait compter qui est propre à
l’algorithme (c.-à.-d. à l’exclusion de l’entrée et la sortie des données).
Complexité d’un algorithme. À nouveau, pas de définition précise toute de suite (à revoir
vers la fin du cours). Idée la plus simple : c’est le nombre d’instructions élémentaires executées, vu
comme fonction de n (pour factorisation), ou comme fonction du nombre de mots dans L (pour
une liste), . . ..
En pratique, il n’y a pas de formule exacte explicite pour le nombre d’instruction élémentaires
(sauf quelques algorithmes très particuliers). On se contente de l’ordre de magnitude (croissance
de la fonction avec n, avec le nombre de mots dans
√ lan liste). Combien d’instructions simples faut2
t-il pour factoriser n (à peu près) ? log(n), n , n, e . . . ? Combien en faut-il pour trier une liste
à n éléments ?
Notations O, Ω, Θ. Soit f : N → R+ une fonction (peut-être non définie en quelques petites
n ∈ N). On note
O(f ) = {g : N → R+ | g(n) ≤ Cf (n) pour tout n assez grand et une constante convenable C > 0},
Ω(f ) = {g : N → R+ | g(n) ≥ Cf (n) pour tout n assez grand et une constante convenable C > 0},
Θ(f ) = O(f ) ∩ Ω(f ).
On utilise une notation analogue pour des fonctions f : [a, +∞[→ R+ , des fonctions f : N2 →
R+ etc. Par exemple, si f : N2 → R+ , g : N2 → R+ , alors g ∈ O(f ) s’il existe C > 0 telle
que g(m, n) ≤ Cf (m, n) pour tout (m, n) avec ||(m, n)|| assez grand, || . || étant n’importe quelle
norme sur R2 . (Toutes les normes sur R2 étant équivalentes, cette définition est indépendente du
choix de la norme.)
Remarques. (1) C’est la notation dite de Landau, mais déjà utilisée (dans le cas de O) par
P. Bachmann en 1894, alors que ni Bachmann ni Landau n’utilisaient les notations Ω(f ) et Θ(f ).
(2) La définition de Ω(f ) n’est pas celle utilisée en théorie analytique des
nombres, où g ∈ Ω(f )
signifie (f (n), g(n) > 0 pour tout n assez grand) et lim sup g(n)/f (n) > 0. (3) On rencontre
souvent l’écriture g = O(f ) à la place de g ∈ O(f ). Cette pratique est à éviter devant un jury de
concours.
√
2
Exemples. (i ) n ∈ O(n), (log n)a ∈ O(nc ) quelque soit a, c > 0, O(en ) ⊆ O(en ).
(ii ) Le pseudoprogramme ci-dessus s’exécute en n + 3Np (n) + 2Ni (n) opérations élémentaires.
Comme Np (n) = b n2 c et Ni (n) = b n+1
c, on constate qu’il est dans Θ(n) (sauf si on prend en
2
compte le temps de division de i par 2 comme blog2 ic + 1).
La formule de Stirling. Elle permet d’insérer la fonction factorielle et les coefficients binomiaux dans l’hierarchie des fonctions. Le résultat suivant est un peu plus précis, car elle fournit
un encadrement de la fonction factorielle par des fonctions de forme exponentielle.
3
Théorème. Pour tout entier n ≥ 1, on a :
n n √
n n √
2πn e1/(12n+1) ≤ n! ≤
2πn e1/12n .
e
e
n n √
Corollaire (formule de Stirling). On a n! ∼
2πn lorsque n → ∞.
e
La formule de Stirling permet également de donner des équivalences à certaines familles de
coefficients binomiaux et de les insérer dans l’hierarchie des fonctions. Par exemple :
2n
22n
∼√ ,
n! ∈ O(nn ),
en ∈ O(n!).
n
πn
La démonstration du théorème relève de l’analyse et elle est donc d’un esprit différent des idées
développées dans ce cours. Elle est donc reportée en annexe et se trouve à la fin de ce document.
L’étude des algorithmes
Pendant le reste de ce cours, nous allons pour la plupart du temps étudier différents algorithmes
ou parfois comparer plusieurs algorithmes ayant la même finalité. En règle générale, l’étude d’un
algorithme consiste en les points suivants (dont certains pourraient être laissés en partie ou en
totalité en exercice) :—
(1) déscription informelle de l’algorithme, parfois à l’aide d’exemples ;
(2) redaction de l’algorithme en pseudocode ,
(3) preuve que l’algorithme se termine et estimation de sa complexité ;
(4) preuve que l’algorithme fournit effectivement le résultat désiré ;
(5) éventuellement, quelques remarques diverses, par exemple comparaison avec d’autres algorithmes ayant la même finalité.
Remarque. Le plus souvent, on connaı̂t plusieurs algorithmes ayant la même finalité. Par
exemple, on connaı̂t plusieurs algorithmes de factorisation d’entiers. De même, la plupart algorithmes possèdent plusieurs variantes et les discriptions peuvent varier légèrement selon les auteurs. On veillera à ce que le pseudocode dans l’étape (2) correspond bien à l’algorithme décrit
informellement au point (1), et non pas à une variante ou à un autre algorithme ayant la même
finalité.
Algorithmes de tri
Il y en a beaucoup. Le choix d’utilisation dépend du contexte. Soit E un ensemble muni
d’un ordre total ≤. Un tableau d’éléments de E est une application T : [[1, n]] → E (ou d’un
autre ensemble d’entiers consécutifs vers E). Ici, comme ailleurs, [[d, f ]] (où d < f sont deux
réels) désigne l’ensemble des entiers i vérifiant d ≤ i ≤ f . Un sous-tableau d’un tableau T
est un tableau T 0 paramétré par une partie [[d, f ]] de [[1, n]] formée d’entiers consécutifs tel que
T 0 [i] = T [i] lorsque i ∈ [[d, f ]]. Si T est un tableau d’éléments de E, trier T signifie ranger les
éléments de T en ordre croissant (ou décroissant), c’est-à-dire trouver (algorithmiquement) une
permutation π de [[1, n]] telle que T [π(1)] ≤ T [π(2)] ≤ · · · ≤ T [π(n)]).
4
Les algorithmes qui nous allons décrire s’appliquent à un ensemble totalement ordonné E et
à un tableau T dont les coefficients sont des éléments arbitraires de E. Le principe de base de ces
algorithmes est le test de comparaison de deux éléments de E et il est sous-entendu qu’on dispose
d’une méthode d’effectuer un tel test. Par hypothèse donc, ces algorithmes sont génériques. Voir
le paragraphe Quelques autres algorithmes de tri un peu plus loin pour une discussion brève
de quelques algorithmes spéciaux, adaptés aux ensembles E possédant des propriétés particulières
ou dont les éléments possèdent une représentation particulière.
Opérations élémentaires : test de comparaison de deux éléments de E, échange de deux
éléments d’un tableau, extraction d’un sous-tableau.
Remarque. Une liste L d’éléments d’un ensemble E quelconque est une famille de tableaux
d’éléments de E (de longueur variable) indexée par N (ou par les sommets d’un arbre A), tel que
L(n+1) est obtenu de L(n) (ou L(s0 ) est obtenu de L(s) si (s, s0 ) est une arête de A) par l’ajout ou
la suppression d’un élément de E (y compris la création ou suppression d’une liste à un élément).
Ce sont des opérations élémentaires sur une liste.
L’échange de deux éléments d’un tableau est fait par la suppression de l’un des éléments, puis
de l’autre, puis par l’ajout du deuxième élément dans l’ancienne position du premier et l’ajout du
premier élément dans l’ancienne position du second. Cela fait 4 opérations élémentaires sur une
liste, un nombre indépendant du tableau.
La complexité d’un algorithme de tri est donc mesurée par le nombre de tests de comparaison.
Si on y ajoute les échanges necéssaires, on reste dans le même ordre de complexité Θ.
Tri par insertion. C’est l’algorithme le plus souvent utilisé par des joueurs de cartes. La
première étape est le tri du sous-tableau (T [1], T [2]). On commence donc en comparant T [2] à
T [1] : si T [2] < T [1], on échange T [2] et T [1] ; dans le cas contraire, on laisse T [1] et T [2] en
place. En général, si j ≥ 2, alors après j − 1 étapes on a une permutation πj−1 de {1, 2, . . . , j − 1}
telle que T [πj−1 (1)] ≤ T [πj−1 (2)] ≤ · · · ≤ T [πj−1 (j − 1)] et le reste du tableau est inchangé. Si
T [j] ≥ T [πj−1 (i)] pour tout i ≤ j − 1, on ne fait rien. Sinon, on bouge T [j] à gauche pas à pas
jusque tous les éléments à gauche de T [j] sont ≤ T [j].
Cela signifie qu’on interchange T [j] et T [πj−1 (j − 1)], puis T [j] et T [πj−1 (j − 2)] et ainsi
de suite jusqu’à ce que T [j] arrive en bonne position. (Si celle-ci est la position i, on a alors
πj = πj−1 ◦ (j, i, i + 1, · · · , j − 1).)
Après n − 1 étapes, on obtient une permutation πn des indices tel que T [πn (1)] ≤ T [πn (2)] ≤
· · · ≤ T [πn (n)] (uniquement déterminé par l’algorithme et unique si les T [i] sont deux-à-deux
distincts).
Dans la redaction du pseudocode on se sert d’un tableau variable X, (donc X[i] vaut T [i] au
début et T [πn (i)] à la fin).
procédure: triins(T ) (entrée : T , un tableau à n éléments ; sortie : T trié par ordre croissant)
variables locales: X (un tableau à n éléments), j, k (entiers vérifiant 1 ≤ k < j ≤
n)
X←T
pour j de 2 à n
k =j−1
tantque (k > 0 et X[k] > X[k + 1])
échanger X[k + 1] et X[k]
k ←k−1
fintantque
5
finpour
retourner X
Pour chacune des n − 1 valeurs de j, il y a j − 1 valeurs de k = j − 1, j − 2, . . ., 1 et pour
chacune de ces valeurs de k il faut faire un test de comparaison entre X[k + 1] et X[k]. Il y a donc
au total
n
X
n(n − 1)
(j − 1) =
2
j=2
tests, et à l’issu de chaque test on effectue au plus un échange. La complexité de l’algorithme
appartient donc à Θ(n2 ).
Pour prouver que la sortie de l’algorithme est effectivement ce que l’on attend, il suffit de
vérifier que, pour tout j ∈ 2, 3, . . . , n, le sous-tableau (X[1], X[2], ..., X[j − 1]) de X à l’issu de la
boucle est trié par ordre croissant. Lorsque j = 2, c’est clair. Si c’est vrai pour une valeur de j, c’est
également vrai pour j remplacé par j +1, car la boucle soit laisse X[j] fixe si X[i] ≤ X[j] pour tout
i < j soit insère X[j] entre X[i − 1] et X[i] où i est l’unique indice tel que X[i − 1] < X[j] ≤ X[i].
Tri bulle (bubble sort en anglais). Ainsi nommé parce que, le tableau étant écrit verticalement,
les éléments remontent vers leur position naturelle par comparaison avec l’élément juste au dessus,
comme des bulles dans un aquarium. (À la fin les plus grands éléments seront en haut.)
En plus de détail, on commence avec T [1] : si T [1] > T [2] on échange T [1] avec T [2] puis
successivement avec T [3], T [4] jusqu’à ce qu’on arrive à un indice i tel que T [1] < T [i]. Si i ≤ n−2,
on recommence avec T [i + 1] et T [i + 2], les échangeant si T [i + 1] > T [i + 2] et ainsi de suite. On
remonte alors jusqu’à T [n]. Notons qu’à l’issu de ce procès, T [n] ≥ T [j] quelque soit j < n. Ensuite,
on recommence avec le nouveau T [1] en le comparant avec T [2] les échangeant si T [1] > T [2] et
ainsi de suite. Puisque T [n] ≥ T [j] lorsque j < n, on s’arrête en T [n − 1]. Si on écrit le tableau de
gauche à droite, c’est T [1], T [2], . . ., T [n − 1] qui bougent à droite alors que dans l’algorithme de
tri par insertion c’est T [2], T [3], . . ., T [n] qui bougent à gauche. Le pseudoprogramme est donc
procédure: tribulle(T ) (entrée : T , un tableau à n éléments ; sortie : T trié par ordre
croissant)
variables locales: X (un tableau à n valeurs), j, k (entiers vérifiant 1 ≤ k ≤ j ≤
n − 1)
X←T
pour j de n − 1 à 1
pour k de 1 à j
si X[k + 1] < X[k] alors échanger X[k + 1] et X[k]
finsi
finpour
finpour
retourner X
Ici, pour chaque j ∈ {1, 2, . . . , n − 1}, k prend j valeurs et pour chaque k ilPy a un test (si
n−1
X[k + 1] > X[k] ou non) et éventuellement un échange. À nouveau donc, il y a j=1
j = n(n−1)
2
tests, et la complexité appartient à Θ(n2 ).
À l’issu de l’itération sur j, on voit que X[i] ≤ X[n − j + 1] lorsque i < n − j + 1 et que
la partie (X[n − j + 1], · · · , X[n]) du tableau est trié par ordre croissant. En particulier, lorsque
j = n − 1, on a X[1] ≤ X[2] et (X[2], X[3], . . . , X[n]) est trié par ordre croissant. Donc T est trié
par ordre croissant.
6
Tri par selection. On cherche un indice k tel que T [k] = min1≤i≤n T [i] puis on échange T [k]
et T [1]. Ensuite, on cherche un indice ` ≥ 2 tel que T2 [`] = min2≤i≤n T2 [i], puis on échange T2 [`]
et T2 [2]. Et ainsi de suite.
Cela necéssite savoir calculer un indice i tel que T [i] soit minimal, et d’étudier la complexité
de cela.
Remarquons que nous avons déjà un algorithme pour trouver le maximum, car dans tribulle,
chaque itération sur j a pour effet de ramener un élément maximal d’un sous-tableau à son
extrémité droite. Mais l’information sur l’indice de départ est perdue.
La procédure suivante fait ce qu’on a besoin.
procédure indmin(T ) (entrée : T un tableau à n éléments ; sortie : le plus petit indice i tel
que T [i] ≤ T [j] pour tout j ∈ {1, 2, . . . , n})
variables locales: indprov (un entier, valeur provisoire de l’indice cherché)
indprov = 1
pour j de 2 à n
si T [j] < T [indprov], indprov ← j
finsi
finpour
retourner indprov
Ici, il y a n−1 valeurs de j, et pour chacune il y a 1 ou 2 opérations élémentaires. La complexité
de la procédure appartient donc à Θ(n).
La procédure de tri par sélection est alors fournie par le pseudocode suivant (où on note X[[j,n]]
le sous-tableau de X indexé par [[j, n]]) :
procédure trisél(T ) (entrée : T , un tableau à n éléments ; sortie : T trié par ordre croissant)
variables locales: X (un tableau à n valeurs), j, k (entiers vérifiant 1 ≤ j ≤ n − 1,
j ≤ k ≤ n)
X←T
pour j de 1 à n − 1
k ← indmin(X[[j,n]] )
si j 6= k, échanger X[j] et X[k]
finsi
finpour
retourner X
On voit de la même manière que précédemment que la complexité de trisél appartient à
O(n2 ) et que l’algorithme retourne bien T trié en ordre croissant.
Ces algorithmes ont tous une complexité appartenant à Θ(n2 ). Peux-t-on faire mieux ?
La réponse à cette question est oui. L’idée nouvelle de base est de diviser T un deux tableaux
plus petits T1 et T2 , puis de diviser T1 et T2 chacun et ainsi de suite, jusqu’à l’obtention de tableaux
de petite taille, que l’on tri puis intercale pour retouver les tableaux plus grands déjà triés, puis
enfin on intercale T1 et T2 triés pour retrouver T1 trié.
Il y a plusieurs algorithmes de ce genre, qui se distinguent surtout selon la méthode de division des tableaux. Puisqu’ils utilisent tous l’intercalage de tableaux déjà triés, nous examinerons
d’abord la complexité de cela.
Intercalation de deux tableaux triés. Soient T1 , T2 deux tableaux de taille n et m respectivement, triés par ordre croissant. Le tableau T obtenu en intercalant T1 et T2 est donc de taille
m + n (on ne supprime pas les éléments communs et, en cas d’égalité, on n’interchange pas l’ordre
des valeurs et on place celles provenant de T1 avant celles provenant de T2 ).
7
procédure intercale (T1 , T2 ) (entrée : T1 , T2 deux tableaux triés par ordre croissant, de
tailles respectives n et m ; sortie : le tableau obtenu en intercalant T1 et T2 , trié par ordre croissant)
variables locales: X (une liste), j, k (des entiers variant respectivement de 1 de 1 à n et
de 1 à m)
X ← ∅, j ← 1, k ← 1
tantque (j ≤ n et k ≤ m)
si T1 [j] ≤ T2 [k]: X ← (X, T1 [j]), j ← j + 1
sinon X ← (X, T2 [k]), k ← k + 1
finsi
finpour
retourner X
Le nombre de tests de comparaison est égal à m + n − 1 et, après chaque test, on ajoute
un élément à la liste. Ces deux opérations constituent chacune une opération élémentaire. La
complexité de l’algorithme appartient donc à Θ(n + m), La preuve de l’algorithme est claire.
Tri fusion. On divise T en 2 parties aussi égales que possible (c’est-à-dire T1 = T[[1,n/2]] ,
T2 = T[[n/2+1,n]] lorsque n est pair et T1 = T[[1,(n−1)/2]] , T2 = T[[(n+1)/2,n]] lorsque n est impair pour
fixer les idées). On continue ainsi par divisions successives jusqu’à ce que tous les tableaux soient
formés d’un seul élément. Puis on remonte, en intercalant les deux parties triées pour obtenir le
sous-tableau précédent.
La situation est mieux décrite en utilisant le langage des arbres binaires. Un arbre binaire
entier fini est un ensemble fini A muni d’une structure dont la définition se fait par récurrence
sur le cardinal de A. Le cardinal de A est toujours impair et les éléments de A sont appelés les
sommets ou nœuds. Le structure est formée d’un élément distingué rA de A, appelé sa racine,
d’un sous ensemble de A dont les éléments s’appellent les feuilles et d’un sous-ensemble de A × A
dont les éléments s’appellent des arêtes. Lorsque A contient un seul élément, cet élément est à
la fois la racine et une feuille, alors que l’ensemble des arêtes est vide. Supposons que A soit de
cardinal n ≥ 3. Alors on a une partition de A en trois ensembles, l’un contenant pour seul élément
la racine de A et l’autre ou les deux autres, que l’on note B et C étant des sous-arbres binaires
de A, qu’on appelle les fils de A. L’ensemble des feuilles de A est alors la réunion des ensembles
des feuilles de B et de C. L’ensemble des arêtes de A et la réunion des ensembles des arêtes de B
et de C, à laquelle on ajoute deux nouvelles arêtes (rB , rA ) et (rC , rA ) qui joignent respectivement
la racine de B à celle de A et la racine de C à celle de A.
Soit A un arbre binaire entier et soit x, y deux sommets de A. Un chemin joignant x et y
et une séquence de sommets x = x0 , x1 , x2 , . . ., xn = y telle que (xi−1 , xi ) est une arête pour
tout 1 ≤ i ≤ n. L’entier n s’appelle alors la longueur du chemin. On voit immédiatement par
récurrence sur A que deux sommets sont joints par au plus une arête, et que si x 6= rA est un
sommet, il existe un unique chemin joignant x à rA . Par définition, le niveau de rA est 0 et, si
x est un sommet autre que rA , le niveau de x est la longueur du chemin que le joint à rA . La
hauteur de A est le maximum des niveaux de ses sommets.
Un isomorphisme entre deux arbres binaires entiers A et A0 est une bijection de A sur A0
qui induit une bijection entre les arêtes. Un isomorphisme transforme la racine de A en celle de
A0 et l’ensemble des feuilles de S en celui de A0 .
Un arbre binaire entier a une représentation géométrique simple. Traditionnellement, on
met la racine sur une ligne toute seule en haut (et non pas en bas comme chez les arbres végétaux),
puis ses deux fils (les racines de ses deux fils) sur la ligne suivante, l’arête entre la racine et chaque
fils étant représentée par un segment droit. Ensuite, on répète, en mettant tous les sommets d’un
même niveau sur la même ligne.
8
Soit donc T un tableau à n éléments. On lui associe un arbre binaire A construit de la manière
suivante par récurrence sur n. Les sommets de A sont certains sous-tableaux de T et la racine de
A est T lui même. Si n = 1, A ne contient que le seul sommet T . Si n ≥ 2, les deux fils de la racine
T de A sont les arbres associés aux deux sous-tableaux de T indexés par [1, n2 ] et par [ n2 + 1, n]
] et par [ n+1
, n] lorsque n est impair. Les feuilles de A sont les
lorsque n est pair et par [1, n−1
2
2
sous-tableaux à un élément T [1], T [2], . . ., T [n]. Il est clair qu’il s’agit d’un arbre binaire entier.
Le diagramme suivant montre l’arbre lorsque T a 11 éléments ; T[[a,b]] désigne le sous-tableau de
T indexé par les entiers appartenant à l’intervalle [a, b] et (T [i]) désigne le sous-tableau contenant
l’unique élément (T [i]). La hauteur est alors égale à 4.
T
T[[1,5]]
T[[1,2]]
T[[6,11]]
T[[3,5]]
T[[6,8]]
T[[4,5]]
(T [1])
(T [2])
(T [3])
T[[9,11]]
T[[7,8]]
(T [6])
(T [4]) (T [5])
T[[10,11]]
(T [9])
(T [7]) (T [8])
(T [10]) (T [11])
Proposition. (i ) À isomorphisme près, l’arbre A ne dépend que de la taille n de T , en non
de T lui-même.
(ii ) Si T 0 est un sous-tableau de niveau k, alors la taille de T 0 se situe dans l’intervalle [ n+1
−
2k
n−1
1, 2k + 1].
On suppose que n ≥ 2 et on note d l’unique entier tel que 2d < n ≤ 2d+1 .
(iii ) On a h(A) = d + 1.
(iv ) Si k < h(A), alors A contient 2k sommets de niveau k. En plus, A contient 2(n − 2d )
sommets de niveau h(A).
Démonstration. (i ) On voit aussitôt que si T est de taille n, alors A est isomorphe à l’arbre An
dont les sommets sont certains entiers ≥ 1 (pas forcément distincts) qui sont précisés (en même
temps que les arêtes) inductivement comme suite :
(1) A1 est l’arbre avec unique sommet 1.
(1)
(2)
(2) Si n est pair, An est obtenu en prenant deux copies disjointes An/2 et An/2 de An/2 puis
(1)
en y ajoutant n comme racine, une arête joignant n à la racine de An/2 et une autre joignant n à
(1)
la racine de An/2 .
(3) Si n est impair, An est obtenu en prenant une copie de A(n−1)/2 et une autre de A(n+1)/2
puis en ajoutant n comme racine, une arête joignant n à la racine de A(n−1)/2 et une autre joignant
n à la racine de A(n+1)/2 .
soit n2 soit n+1
. Elle est donc
(ii ) La taille des tableaux situés au niveau 1 de A est soit n−1
2
2
n+1
située entre n−1
et
.
Par
récurrence
sur
k,
on
voit
que
la
taille
des
tableaux
situés
au niveau k
2
2
n+1
n−1
de A appartient à [ 2k − 1, 2k + 1].
9
(iii ) et (iv ) Raisonnons par récurrence sur n. D’après le (i ), les valeurs de h(A) et de d ne
dépendent que de n : on les note respectivement hn et dn . On note Nn (k) le nombre de sommets
de A de niveau k. Lorsque n = 2, on a hn = 1 et dn = 0 ; on trouve N2 (0) = 1 et N2 (1) = 2. Donc
tout est en règle. De même pour n = 3.
Supposons donc que n ≥ 4.
Si n est pair, alors n > n2 ≥ 2 et hn = hn/2 + 1 d’après la construction de An . Puisque
2d +2 ≤ n ≤ 2d+1 , on a également dn = dn/2 +1. Par l’hypothèse de récurrence, on a hn/2 = dn/2 +1,
d’où hn = dn +1. De même, la construction de An implique Nn (0) = 2 et que Nn (k) = 2Nn/2 (k −1)
pour tout k ≥ 1. Par l’hypothèse de récurrence, Nn/2 (`) = 2` lorsque ` < hn/2 et Nn/2 (hn/2 ) =
2(n/2 − 2dn/2 ). Les formules prévues pour Nn (k) en découlent.
≥ 2, n+1
< n et hn = max(h(n−1)/2 + 1, h(n+1)/2 + 1) d’après la
Si n est impair, alors n−1
2
2
n+1
construction de An . Puisque 2 = n−1
+
1, l’hypothèse de récurrence implique que h(n+1)/2 =
2
n−1
h(n−1)/2 sauf lorsque 2 est une puissance de 2, auquel cas h(n+1)/2 = h(n−1)/2 + 1. Dans tout
les cas, donc, hn = h(n+1)/2 + 1. Comme 2dn + 1 ≤ n ≤ 2dn +1 − 1, on a dn = d(n+1)/2 + 1. Par
l’hypothèse de récurrence, on a h(n+1)/2 = d(n+1)/2 + 1, d’où hn = dn + 1. Le cas exceptionnel n−1
2
une puissance de 2 équivaut en fait à n = 2dn + 1. Dans ce cas, on voit directement que Nn (k) = 2k
pour tout k < hn et que Nn (hn ) = 2. (L’arbre A2b +1 se construit à partir de A2b en ajoutant deux
arêtes à la base du sommet en bas à droite.) Puisque n − 2dn = 1, on obtient la formule prévue
pour Nn (hn ). Dans les autres cas, h(n−1)/2 = h(n+1)/2 et on trouve comme dans le cas n pair que
Nn (k) = 2k lorsque k < hn et que
n − 1
n + 1
Nn (hn ) = N n−1 (h n−1 ) + N n+1 (h n+1 ) = 2
− 2dn −1 + 2
− 2dn −1 = 2(n − 2dn )
2
2
2
2
2
2
comme prévu.
Théorème. La complexité de tri fusion appartient à Θ(n log n).
Démonstration. D’après l’étude de l’algorithme d’intercalation de deux tableaux triés, le
nombre de tests de comparaison necéssaires pour intercaler deux tableaux triés de tailles n1 et n2
est égal à n1 + n2 − 1. Soit h la hauteur de l’arbre associé au tri d’un tableau à n éléments en
utilisant le tri fusion.
Si 1 < k < h, il y a 2k sous-tableaux de niveaux k, ce qui fait 2k−1 couples de tableaux à
intercaler. La taille de chaque sous-tableau de niveau k appartient à l’intervalle [ n+1
− 1, n−1
+ 1]
2k
2k
n+1
n−1
et l’intercalation de deux tableaux de niveaux k nécessite donc entre 2k−1 − 3 et 2k−1 + 1 tests de
comparaison. Le nombre de tests de comparaison nécessaires pour intercaler les 2k−1 couples de
sous-tableaux de niveau k est donc situé entre n + 1 − 3 · 2k−1 et n − 1 + 2k−1 .
Les sous-tableaux de niveaux h sont des feuilles. Ils sont en nombre 2(n − 2h−1 ). Alors n − 2h−1
tests de comparaison sont nécessaires pour créer les sous-tableaux à deux éléments de niveau h−1.
Soit C(n) le nombre de tests de comparaison utilisé par le tri fusion pour trier un tableau à n
éléments. On tire de la discussion précédente l’encadrement
h−1
X
k−1
(n + 1 − 3 · 2
h−1
) + (n − 2
) ≤ C(n) ≤
k=1
h−1
X
(n − 1 + 2k−1 ) + (n − 2h−1 ),
k=1
ce qui, après simplification, donne
h(n + 1) − 2h+1 + 2 ≤ C(n) ≤ h(n − 1).
Puisque 2h−1 < n ≤ 2h , on en conclut que la complexité de tri fusion appartient bien à Θ(n log n).
10
Tri par tas (heapsort en anglais). L’idée s’inspire de la stratégie d’une compétition par
élimination. L’équipe T [1] joue contre l’équipe T [2] et le gagnant joue ensuite contre le gagnant
parmi les équipes T [3] et T [4]. Cela peut être représenté par un arbre : ici, on veut trier le tableau
à 11 éléments (535, 102, 917, 283, 756, 835, 512, 729, 067, 610, 345). Comme T [1] > T [2], T [1] bat
T [2] qui doit alors affronter le gagnant entre 917 et 283, soit 917. Il est clair que le plus grand
élément (ici 917) sera le gagnant ; on remarque toutefois que l’autre finaliste est 729, ce qui n’est
pas le deuxième élément du tableau par ordre de magnitude (ce qui devrait faire réfléchir les
organisateurs de tournois par élimination . . .).
On pourrait régler ce problème en rejouant le tournoi sans le gagnant ; alors le deuxième
remontera à la position suprême, puis rejouer le tournoi sans le gagnant ni le deuxième pour
déterminer le troisième, et ainsi de suite. On obtient ainsi effectivement un algorithme de tri. Mais
un tournoi à k concurrents a besoin de k − 1 jeux ou comparaisons
P pour déterminer le gagnant : si
donc on commence avec un tableau à n éléments, il faudrait nk=1 (k − 1) = n(n−1)
comparaisons
2
2
pour le trier jusqu’au bout, et l’algorithme est donc à nouveau de complexité Θ(n ).
Afin d’obtenir un algorithme plus rapide, il faudra donc introduire une autre idée. On remarquera que l’arbre du tournoi a la propriété que toute chaı̂ne (lue du bas vers le haut) est croissante,
ou encore que chaque fils est plus petit que son père. On peut donc l’interpréter comme un tri
partiel du tableau. Par ailleurs, il se calcule en n − 1 comparaisons et son hauteur est dlog2 ne.
Il a toutefois l’inconvénient que la plupart des éléments du tableau y sont répétés plusieurs
fois : la première étape de l’algorithme de tri par tas est donc de le remplacer par un tas, c’est-àdire un arbre binaire où chaque fils est strictement plus petit que son père. Il y a plusieurs manières
de construire un tas à partir d’un tableau. Par exemple, on peut procéder par une méthode de
condensation de l’arbre précédent, mais ce n’est pas facile à décrire rigoureusement. Une autre
méthode consiste à d’abord construire l’arbre binaire associé à T , dont la racine est T [1], ses
deux fils sont T [2] et T [3] et, en général, les deux fils de T [i] sont T [2i] et T [2i + 1]. Contrairement
au cas de l’arbre utilisé dans la discussion du tri fusion, il ne s’agit pas, en général, d’un arbre
binaire entier ; ce sera le cas si et seulement si n est impair. Dans le cas où n est pair, le sommet
T [ n2 ] a l’unique fils T [n].
Le tri par tas procède alors en deux étapes, dont la première consiste en la conversion en un
tas de l’arbre binaire qui vient d’être décrit. La deuxième étape consiste en la création du tableau
à partir de ce tas.
On convertit l’arbre binaire en tas en travaillant du bas vers le haut. Considérons d’abord le
cas d’un ’arbre binaire avec racine a et deux feuilles b et c. Il est converti en tas à l’aide de deux
11
tests de comparaison. D’abord, on test si a < b et on échange a et b si la réponse est affirmative.
Ensuite, on compare le plus grand de a et de b (qui est devenu racine) avec c, et on les échange si
besoin.
Si T [i] est tel que T [2i] et T [2i + 1] sont déjà les racines d’un tas, on construit un tas avec
racine en position T [i] de la manière suivante. Si T [i] > T [2i] et si T [i] > T [2i + 1], il s’agit d’èj
d’un tas. Si T [i] < T [2i], on les échange ; si T [i] > T [2i] mais T [i] < T [2i + 1], on échange T [i] et
T [2i + 1]. En procédant ainsi, on descend T [i] par échanges successifs jusqu’il trouve une position
où l’arbre redevient un tas. Ce sera le cas lorsque T [i] est plus grand que ces fils (ou se trouve en
position de feuille). Le nombre de tests de comparison nécessaires est égal au plus à la hauteur
h := blog2 nc de l’arbre. Puisque l’arbre possède n sommets, la complexité de cette première étape
appartient à O(n log n).
La deuxième étape de l’algorithme de tri par tas est donc de créer le tableau trié à partir du
tas ainsi construit. On sait que la racine du tas est le plus grand élément de T et on la place dans
une liste qui devriendra au fur et à la mesure le tableau T trié. On crée alors un nouvel arbre
binaire à n − 1 sommets, obtenu du premier en remplaçant sa racine par l’une des feuilles, qui est
alors supprimée de sa position initiale. Le point essentiel est que les fils de la racine sont encore
des tas. À partir de cet arbre on crée à nouveau un tas, ce qui se fait en descendant la racine dans
l’arbre par échanges entre pères et fils. À l’issu de ces échanges, dont il y a au plus h, la nouvelle
racine est à nouveau le plus grand élément du tas, donc le deuxième élément de T et on le place
dans la liste qui deviendra T trié. Ensuite, on recommence la procédure en créant un arbre à n − 2
sommets en remplaçant la racine du précédent par l’une de ces feuilles. En continuant ainsi, on tri
le tableau après au plus hn tests de comparaison. Puisque h = blog2 nc, on a hn ∈ O(n log n). La
complexité de la première étape de l’algorithme appartenant ègalement O(n log n), la complexité
totale du tri par tas appartient, comme celle du tri fusion, à O(n log n).
Une borne inférieure pour la complexité d’un algorithme de tri par tests de
comparaison
Rappelons que tous les algorithmes décrits jusqu’ici utilisent les tests de comparaison entre
différents éléments de l’ensemble E.
Théorème. Tout algorithme de tri générique qui procède par tests de comparaison a une
complexité d’au moins Ω(n log n).
La démonstration est proposée en exercice (voir la feuille 2, Exercice 3). Ensuite, certains
algorithmes procèdent par l’échange de deux éléments qui sont dans le mauvais ordre. Au niveau
des permutations, cela correspond à effectuer une transposition.
Proposition. Toute permutation π de n objets s’écrit comme produit de n − c(π) transpositions, où c(π) désigne le nombre de cycles disjoints de π (en comptant les éléments fixes comme
des 1-cycles).
Autrement dit, puisque c(n) ≥ 1, au plus n − 1 échanges sont en principe nécessaires pendant
le tri. Les démonstrations sont proposées en exercice (voir les feuilles 2 et 3).
12
Cela semble conduire à un paradoxe, dans le sens que Θ(n log n) comparaisons sont nécessaires
mais, ou bien seulement n − 1 entre elles puissent conduire à des échanges ou bien on effectue
davantage d’échanges que nécessaire.
Remarque. En fait, la démonstration du théorème montre que tout algorithme de tri de n
objets par tests de comparaison nécessite au moins S(n) := dlog2 n!e tests (voir l’Exercice 3 de la
feuille 2). La question se pose donc de connaı̂tre le nombre minimal de tests nécessaires, comme
fonction de n. Il est facile de construire des algorithmes de tri utilisant dlog2 ne tests lorsque
n ≥ 4. Pour tout entier n ≥ 2, il existe un algorithme, appelé (appelé parfois
ou
Pn insertion-fusion
3
algorithme de Ford-Johnson) dont le nombre de tests de comparaison est k=1 dlog2 4 k e, somme
que nous désignerons par F (n). On trouve que F (n) = S(n) quelque soit n ≤ 11 et pour n = 21,
n = 22. L’algorithme est donc optimal (du point de vue du nombre de tests de comparaison)
pour ces valeurs de n. On a S(12) = 29 alors que F (n) = 30 et on peut montrer (à l’aide de
calculs sur ordinateur) qu’il n’y a pas de méthode de trier 12 objets avec seulement 29 tests. Donc
l’algorithme de Ford-Johnson est optimal aussi lorsque n = 12. Mais on connaı̂t des valeurs de
n pour lesquels cet algorithme n’est pas optimal, dont n = 47 est la plus petite. En général, on
ne connaı̂t pas le nombre minimal Smin (n) de comparaisons nécessaires pour trier n objets. Bien
évidemment, S(n) ≤ Smin (n) ≤ F (n) quelque soit n.
Le tri rapide
L’algorithme appelé aujourd’hui tri rapide (quicksort en anglais) a été développé à partir
du début des années 1960. Le principe derrière cet algorithme est l’utilisation d’un pivot p ∈ E
convenablement choisi, c’est-à-dire on réarrange le tableau T en deux sous-tableaux T[[1,k]] (appelé
tableau à gauche) et T[[k+1,n]] (appelé tableau à droite). Par exemple, on peut supposer que T[[1,k]]
contient tous les coefficients T [i] de T tels que T [i] ≤ p alors que T[[k+1,n]] contient tous les
coefficients tels que T [i] > p. La manière la plus naı̈ve d’effectuer cette opération est de créer
deux listes L− et L+ puis, pour tout i = 1, 2, . . ., n, d’insérer T [i] dans L− ou dans L+ selon que
T [i] ≤ p ou T [i] > p. À la fin, on a L− = T[[1,k]] et L+ = T[[k+1,n]] . La complexité de cette opération
appartient donc à Θ(n). Ensuite, on répète avec chacun des deux sous-tableaux.
La rapidité de l’algorithme dépend du choix du pivot. S’il est choisi de telle façon qu’à chaque
étape le tableau est divisé en deux parties à peu près égales, sa complexité appartient à O(n log n).
Si on ne connaı̂t rien a priori sur les éléments de T , on pourrait choisir T [1] comme pivot (puis
l’élément à gauche de chaque sous-tableau). Mais dans le cas où T est déjà trié par ordre croissant,
on constate que le tableau à gauche ne contient que l’élément T [1] alors que celui à droite contient
les n−1 éléments restants. En répétant, on voit que dans ce cas l’algorithme effectue n−1 divisions
du tableau et que la complexité appartient à Θ(n2 ). On se retrouve donc dans une situation où le
cas d’un tableau déjà trié figure parmi les pires des cas !
Une situation encore plus délicate se produit lorsque T [1] > T [i] pour tout i ∈ {2, . . . , n}. Tel
qu’il vient d’être décrit, l’algorithme tournera éternellement en boucle dans ce cas car le tableau
à droite est alors vide. Pour éviter un problème de cette nature, il faut modifier l’algorithme
en ajoutant des instructions indiquant comment procéder lorsque l’élément le plus grand d’un
sous-tableau se trouve à gauche de ce sous-tableau. Cette remarque suggère que l’implémentation
pratique de l’algorithme est assez délicate.
Malgré ces complications, le tri rapide est, en pratique, l’un des algorithmes les plus utilisés.
Une analyse mathématique assez délicate montre (et l’expérience le confirme) que le tri rapide est
en moyenne plus rapide que les autres algorithmes si les éléments du tableau sont tirés au hasard
13
dans E.
Quelques autres algorithmes de tri
Les algorithmes décrits jusqu’ici supposent que les éléments de T appartiennent à un ensemble
très grand (en principe infini) et sans structure particulière mise à part l’ordre total. Mentionnons
brièvement quelques algorithmes spéciaux, c’est-à-dire adaptés à des ensembles spécifiques ou qui
ont des propriétés supplémentaires.
Si les éléments de T appartiennent à un petit ensemble E, de cardinalité r fixé disons, on peut
les trier en complexité Θ(n). En effet, si x1 < x2 < · · · < xr sont les différents éléments de E, il
suffit de prendre chacun des éléments de E l’un après l’autre, compter le nombre d’apparitions
dans T puis reconstruire le tableau T trié par ordre croissant comme (x1 , x1 , . . . , x1 , x2 , . . . , xr ).
Cela nécessite rn tests de comparaison. Afin d’éviter toute ambigüité lors de la discussion d’autres
algorithmes de tri basés sur cette procédure, nous le décrivons par le pseudocode suivant :
procédure tripetitE (T ) (entrée : T un tableau dont les éléments appartiennent à un ensemble totalement ordonné E de cardinal r et dont les éléments sont x1 < x2 < · · · < xr ; sortie :
le tableau T trié)
variables locales: X (une liste), i, j (des entiers avec 1 ≤ i ≤ r et 1 ≤ j ≤ n)
X←∅
pour i de 1 à r
pour j de 1 à n: si T [j] = xi , X ← (X, T [j])
finpour
finpour
retourner X
Il s’agit d’un tri stable, c’est-à-dire l’ordre des éléments répétés est respecté.
Tri par ordre lexicographique, tri radix. Rappelons que l’ordre lexicographique sur
R2 est défini par (x, y) < (x0 , y 0 ) ssi soit x < x0 soit x = x0 est alors y < y 0 . Il s’agit d’un ordre total
sur R2 et le principe de sa définition s’étend aisément à un produit cartésien E1 × E2 × · · · × Er
d’ensembles totalement ordonnés Ei . Les tris lexicographiques et tris par radix sont utiles lorsque
les ensembles Ei sont finis et de petit cardinal. Pour tout i ∈ {1, 2, . . . , r}, on note ri le cardinal
de Ei .
Le tri lexicographique tri des tableaux dont les éléments appartiennent à un produit E1 × E2 ×
· · · × Er en triant d’abord par rapport à la première coordonnée, puis par rapport à la deuxième,
et ainsi de suite. Pour être plus précis, on applique tripetitE d’abord à la première coordonnée,
puis on divise T en r1 sous-tableaux selon la première coordonnée. Ensuite, on applique tripetitE
à chacun de ces sous-tableaux et ainsi de suite.
Le tri radix (ou tri par base), tri d’abord par rapport à la dernière coordonnée, puis par
rapport à l’avant dernière et ainsi de suite. Autrement dit, on applique d’abord tripetitE à la
dernière coordonnée. Ensuite, on l’applique à l’avant-dernière coordonnée du tableau ainsi obtenu
(qui n’est donc pas divisé en sous-tableaux), et ainsi de suite.
Le nom tri par base a pour origine l’application au tri d’un tableau d’entiers naturels selon
leur écriture en une base b. Ici, Ei est l’ensemble des chiffres {0, 1, . . . , b − 1} en base b et les entiers
à trier sont présentés sous la forme t = ak−1 bk−1 + ak−2 bk−2 + · · · + a0 , les ai étant des chiffres, t
s’identifiant avec (ak−1 , ak−2 , . . . , a0 ) ∈ E1 × E2 × · · · × Ek (tous les entiers t sont supposés majorés
par bk − 1).
14
Exemple de tri radix. Soit à trier par ordre croissant les nombres (écrits en base 10) : T =
(354, 270, 123, 70, 770, 193).
(a) Première étape : tableau obtenu de T en appliquant tripetitE aux chiffres des unités.
T1 = (270, 70, 770, 123, 193, 354) ;
(b) Deuxième étape : tableau obtenu de T1 en appliquant tripetitE aux chiffres des dizaines.
T2 = (123, 354, 270, 70, 770, 193) ;
(c) Troisième étape : tableau obtenu de T2 en appliquant tripetitE aux chiffres des centaines.
(70, 123, 193, 270, 354, 770), c’est-à-dire T trié par ordre croissant.
Il est clair que les tris léxicographique et radix utilisent r1 r2 · · · rk n tests de comparaison. Leur
complexité appartient donc à Θ(n). Puisque ce ne sont pas des algorithmes génériques, il n’y a
pas de contradiction avec la borne inférieure de dlog2 ne pour le nombre de tests de comparaison
pour un algorithme générique.
En général, on préfère le tri radix au tri lexicographique. Un désavantage des deux est qu’ils
nécessitent O(n) espace mémoire de stockage.
Les algorithmes classiques d’arithmétique de base
Nous étudierons ici les algorithmes classiques (c’est-à-dire ceux qui sont enseignés à l’école)
d’addition, de soustraction, de multiplication et de division euclidienne avec reste, appliqués aux
entiers naturels. On s’intéresse ici donc aux calculs exacts, en non aux calculs approchés effectués
avec de l’arithmétique flottante. Ce point est traité dans les cours d’analyse numérique (ou devrait
l’être).
Un entier relatif peut être représenté comme un couple (ε, n) avec n ≥ 0 et le signe ε ∈
{0, +, −}. Puisque les règles de détermination du signe son faciles (en faisant attention au cas de
zéro) et le signe n’occupe qu’un seul bit, la complexité est, pour l’essentiel, mesurée par les calculs
avec des entiers naturels.
Pour cela, on travaille P
en base b fixée (b > 1 un entier). Tout entier naturel n a donc une
i
représentation unique n = ∞
0 ai b , avec 0 ≤ ai ≤ b − 1 et ai = 0 pour tout n assez grand. Dans ce
contexte, les ai sont appelés les chiffres. Si n 6= 0, on note k − 1 le plus grand entier i tel que ai 6= 0
et n est alors traditionnellement écrit sous la forme (ak−1 ak−2 · · · a0 )b (on omettra les parenthèses
et la base b lorsque b = 10). On a alors soit n = 0 soit bk−1 ≤ n < bk et alors k = blogb nc + 1.
Mise à part l’ajout ou la suppression d’un élément d’une liste (ou l’échange de deux membres),
les opérations élémentaires sont :
(a) Comparaison de deux chiffres (c’est-à-dire des entiers dans l’intervalle [0, b − 1]).
(b) Addition et multiplication des chiffres.
On remarque que la somme de deux chiffres appartient à l’intervalle [0, 2(b − 1)] et que le
produit de deux chiffres appartient à l’intervalle [0, (b − 1)2 ].
(c) La soustraction d’un chiffre d’un entier appartenant à l’intervalle [0, 2b − 1].
(d ) La division euclidienne (quotient et reste) d’un entier naturel dans l’intervalle [0, b2 − 1]
par un chiffre non nul.
(e) multiplication et division euclidienne par une puissance de b. En effet la multiplication par
r
b fait déplacer tous les chiffres r places, en ajoutant des zéros dans les places bs , 0 ≤ s ≤ r − 1.
De même, la division euclidienne de m par br coupe de développement en base b de m en deux
morceaux, le quotient étant (ak−1 ak−2 · · · ar )b et le reste étant (ar−1 ar−2 · · · a0 )b .
15
En informatique, b sera généralement une puissance de 2 (le plus souvent 2, 8 ou 16 ou, dans
le cas d’un processeur 32 ou 64 bits, b = 232 et b = 264 ). Si b est petit, les opérations élémentaires
peuvent se limiter à chercher les valeurs dans un tableau. Un processeur
P programmé pour faire
des calculs rapides avec des entiers longs (c’est-à-dire de la forme i ai bi avec b = 232 ou 264 )
travaille donc à deux niveaux, dont l’un exécute les opérations élémentaires sur les chiffres en base
b, et l’autre exécutes les vraies opérations sur les entiers longs.
Remarque. Puisque 210 = 1024 ce qui dépasse de peu 103 = 1000, le nombre de chiffres d’un
fois le nombre de chiffres en base 10. Cela permet
entier n en base 2 est un peu moins que 10
3
notamment de se donner une idée approximative du nombre de chiffres décimaux d’une puissance
de 2 et du nombre de chiffres en base 2. d’une puissance 10.
Comparaison de deux entiers naturels. Soient m, n deux entiers naturels. On a m ≥ n
si et seulement si, en utilisant l’ordre lexicographique, la liste des chiffres de m est supérieure à
celle des chiffres de n. Ainsi, les entiers naturels m et n peuvent être comparés en appliquant le
tri par ordre lexicographique (ou le tri radix) à leurs chiffres.
Il y a max(blogb (m)c + 1, blogb (n)c + 1) comparaisons de chiffres à faire, et la comparaison
de deux chiffres est une opération élémentaire. La complexité de la comparaison des deux entiers
naturels m et n appartient donc à Θ(max(log(m), log(n))).
Addition. Voici un pseudoprogramme.
procédure add(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b
et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : m + n écrit en base b.)
variables locales : i (indice), γ ∈ {0, 1}, a (chiffre), S (résultat intermédiaire).
si m = n = 0, retourner 0,
sinon, k = blogb max(m, n)c + 1, i ← 0, γ ← 0, S ← 0,
tantque i < k,
si ai + a0i + γ < b, a ← ai + a0i + γ, γ ← 0,
sinon a ← ai + a0i + γ − b, γ ← 1,
finsi
S ← S + abi , i ← i + 1,
fintantque
retourner S + γbk ,
finsi
Dans ce pseudo-code, on nous demande d’additioner S et abi . Mais, en répétant la boucle
tantque, on voit que S prend successivement les valeurs 0, (a000 )b , (a001 a000 )b , . . ., (a00k−1 a00k−2 · · · a000 )b =
m+n et donc S ← S +abi signifie tout simplement ajouter a00i au début de la liste (a00i−1 a00i−2 · · · a000 )b .
Il s’agit donc d’une opération élémentaire.
Il est clair que la complexité de l’algorithme est proportionnelle au nombre d’itérations de
la boucle tantque, soit k ; par conséquent, l’addition de deux entiers naturels m et n se fait en
complexité Θ(log max(m, n)).
Soustraction. On se limite au cas m ≥ n. Voici un pseudoprogramme pour le calcul de m−n.
Cela nécessite un peu d’attention (penser au calcul de 305 − 286 ou de 1000 − 287, par exemple).
La présentation qui suit est légèrement différente de celle que l’on apprend à l’école.
procédure sub(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b
et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : m − n écrit en base b.)
variables locales : i (indice), γ ∈ {0, 1}, a (chiffre), D (résultat intermédiaire).
si m = n, retourner 0,
sinon, k = blogb mc + 1, γ ← 0, i ← 0, D ← 0,
16
tantque i < k,
si ai − a0i − γ < 0, a ← ai − a0i − γ + b, γ ← 1,
sinon a ← ai − a0i − γ, γ ← 0,
finsi
D ← D + abi , i ← i + 1,
fintantque
retourner D,
finsi
Lorsque m 6= n, on a m > 0 et donc ak−1 > 0, et l’hypothèse que m > n assure alors que
ak−1 ≥ a0k−1 et que, si j et le plus grand indice tel que aj 6= a0j , alors aj > a0j . On en tire que a ≥ 0
quelque soit la valeur de i (et que a = 0 lorsque i > j).
Il est clair que la complexité appartient à Θ(log m).
Multiplication. À l’école, on apprend d’abord à multiplier n par a0 , puis par a1 b (c’est-à-dire
par a1 puis décaler tous les chiffres à gauche par une place et ajouter un zéro à la fin), et ainsi de
suite. À la fin, on additionne le tout. Les procédures qui suivent multiplient m par a00 , puis par a01
en décalant les chiffres à gauche
Sur machine, il est plus simple d’intercaler les additions parmi les multiplications.
procédure mult0(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b
et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : mn écrit en base b.)
variables locales : i, j, (entiers naturels), M (résultat intermédiaire).
si (m = 0 ou n = 0), retourner 0,
sinon, i ← 0, j ← 0, M ← 0,
tantque i ≤ k − 1,
tantque j ≤ ` − 1,
M ← add(M, ai a0j bi+j ), j ← j + 1,
fintantque
i ← i + 1,
fintantque
retourner M
finsi
L’utilisation de la fonction add permet de garder les résultats intermédiaires déjà en base
b. La complexité de l’algorithme tel qu’il est rédigé est donc la somme des complexités des
add(M, ai a0j bi+j ) lorsque i varie de 0 à k et j de 0 à `, ce qui est majoré par kl max(k, `), ce
qui est dans O(log m log n max (log m, log n)).
Il est donc clair que l’algorithme se termine. Par ailleurs, sa preuve est immédiate : à la fin de
chaque boucle sur i, M est égal au produit (ai ai−1 · · · a0 )b n ; il est écrit en base b car obtenu en
application la procédure add.
En modifiant l’algorithme un peu, on peut obtenir une complexité dans O(log m log n). Pour
cela, il faut remplacer la ligne M ← add(M, ai a0j bi+j ) par une procédure qui ne change que le
chiffre de bi+j et calcule la quantité à reporter sur le chiffre suivant. Dans le pseudoprogramme
qui suit, on note respectivement quo(u, b) et rem(u, b) le quotient et le reste de division de u par
b, u ayant au plus deux chiffres. (Rappelons qu’il s’agit alors d’opérations élémentaires.)
procédure mult(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b
et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : mn écrit en base b.)
variables locales : i, j, N (entiers naturels), M (résultat intermédiaire, un entier naturel
dont le chiffre devant bh est noté Mh ), γ (chiffre).
si (m = 0 ou n = 0), retourner 0,
17
sinon, i ← 0, M ← 0,
tantque i ≤ k,
j ← 0, γ ← 0,
tantque j ≤ `,
N ← Mi+j + ai a0j + γ, Mi+j ← rem(N, b), γ ← quo(N, b), j ← j + 1,
fintantque
i ← i + 1,
fintantque
retourner M
finsi
On vérifie par double récurrence que Mi+j et γ sont bien des chiffres. Au début, c’est clair
à partir des initialisations. Il suffit alors de constater que si Mi+j et γ sont des chiffres, alors
Mi+j + ai a0j + γ < b2 . Mais les inégalités Mi+j ≤ b − 1, ai a0j ≤ (b − 1)2 et γ ≤ b − 1 entraı̂nent
Mi+j + ai a0j + γ < b2 ≤ (b − 1) + (b − 1)2 + (b − 1) ≤ b2 − 1, d’où l’affirmation.
Illustrons la procédure avec le calcul de 345 fois 377, avec b = 10. On a k = ` = 3. À l’issu
de la boucle sur j lorsque i = 0, M vaut 5 × 377 = 1885 ; c’est donc aussi la valeur de M au
début de la boucle sur j lorsque i = 1. Alors j vaut 0, i + j = 1, M1 = 8 et γ = 0, a1 = 4
et a00 = 7. Par conséquent, Mi+j + ai a0j + γ = 8 + 28 + 0 = 36, et donc M1 devient 6 et γ
devient 3. Lorsque j augmente à 1, i + j = 2, M2 = 8 et γ = 3, a1 = 4 et a01 = 7. Par conséquent,
Mi+j +ai a0j +γ = 8+28+3 = 39, et donc M2 devient 9 et γ est encore égal à 3. Ensuite, j augmente
à 2, i + j = 3, M3 = 1 et γ = 3, a1 = 4, a02 = 3. Par conséquent, Mi+j + ai a0j + γ = 1 + 12 + 3 = 16,
et donc M3 devient 6 et γ devient 1. On voit maintenant pourquoi il est nécessaire de continuer
la boucle jusqu’à j = `, alors que dans la procédure mult0 il suffisait de s’arrêter en j = ` − 1.
Lorsque j = 3, on a M4 = 0, a1 = 4, a03 = 0 et γ = 1. Par conséquent, M4 devient 1. La boucle sur
j est donc terminée, et M est devenu 16965, ce qui est bien 45 × 377. L’étape suivante est donc
d’augmenter i à 2 alors que j et γ sont réinitialisés en 0. Alors M2 = 9, a2 = 3, a00 = 7 et γ = 0, et
donc M2 + a2 a00 + γ = 9 + 21 + 0 = 30, et donc M2 devient 0 et γ devient 3. En continuant ainsi,
on trouve le résultat final 345 × 377 = 130065.
La preuve de l’algorithme consiste à vérifier que, à l’issu de chaque boucle sur i, M est égal
au produit de m et de (a0i a0i−1 · · · a00 )b .
Pour chaque valeur de i et de j, il y a cinq opérations élémentaires (calcul de ai a0j , de Mi+j +ai a0J
puis de Mi+j + ai a0j + γ puis du quotient et du reste après division par b), auquels s’ajoutent un
nombre limité d’initialisations. Comme i varie de 0 à k et j de 0 à `, l’algorithme est toujours en
temps Θ((k + 1)(` + 1)) soit Θ(log m log n).
En particulier, si m ' n, alors la complexité du calcul de mn appartient à O((log n)2 ). Peuxt-on faire mieux et, par exemple, multiplier deux entiers inférieurs ou égaux à n dans un temps
O((log n)c ) avec une constante c < 2 ? La réponse est oui ! (voir plus loin).
Division euclidienne avec reste. On suppose m > 0 (et toujours n ≥ 0) et on cherche les
entiers q, r tels que n = qm + r et 0 ≤ r < m. Rappelons que q et r sont uniquement déterminés.
En effet, q est l’unique entier tel que qm ≤ n < (q + 1)m et, une fois q connu, r et déterminé par
n
la formule r = n − qm. On a également q = b m
c et nous obtenons au passage un algorithme de
calcul de la partie entière bxc pour tout nombre rationnel x.
On suppose que n ≥ m ; dans le cas contraire on a q = 0 et r = n. On pose encore k =
blog mc + 1 et ` = blog nc + 1, de sorte que ` ≥ k. À la différence des algorithmes précédents, on
commence par la recherche du chiffre dominant de q.
Alors m a k chiffres, et on commence en regardant l’entier formé des k chiffres dominants de
n
c.
n, c’est-à-dire b b`−k
18
– Si ce nombre est supérieur ou égal à m, le chiffre dominant de q est celui de b`−k : on a
n
alors mb`−k ≤ n < mb`−k+1 , et il existe un unique chiffre c 6= 0 tel que cm ≤ b b`−k
c mais
n
1
n
(c + 1)m > b b`−k c. Alors c est le chiffre dominant de q : explicitement, on a c = b m b b`−k
cc.
– Dans le cas contraire, on regarde l’entier formé des k + 1 chiffres dominants de n, soit
n
b b`−k−1
c. Le chiffre dominant de q est alors celui de b`−k−1 : on a alors mb`−k−1 ≤ n < mb`−k ,
n
n
et le chiffre cherché est l’unique chiffre c tel que cm ≤ b b`−k−1
c mais (c + 1)m > b b`−k−1
c.
1
n
Explicitement, on a c = b m b b`−k+1 cc.
Par exemple, si on cherche le quotient et le reste de division euclidienne de n = 130165 par
m = 377, on constate que le nombre formé des 3 premiers chiffres de n, soit 130, et inférieur à m.
On est donc dans le deuxième cas, et on constate que 3 × 377 = 1131 ≤ 1301 < 4 × 377 : le chiffre
dominant de q est donc 3.
Ensuite, on répète en remplaçant n par n0 , où n0 = n − cmb`−k dans le premier cas et par
0
n = n − cmb`−k+1 dans le second. Dans les deux cas, le nombre de chiffres baisse strictement, et
on a un algorithme récursif. La seule nouveauté est la présence éventuelle de chiffres nuls. On a
toujours n0 < b`−1 ; le chiffre après c sera nul si et seulement si n0 < mb`−k−1 dans le premier cas
et n0 < mb`−k dans le second.
n
Nous n’avons pas encore discuté du calcul de c. Les formules explicites c = b m1 b b`−k
cc et
1
n
c = b m b b`−k cc font intervenir des divisions par m, et leur utilisation ne constituerait donc pas
une opération élémentaire. Une possibilité serait de d’essayer successivement c = 1, c = 2 jusqu’à
n
n
ce qu’on trouve c tel que cm ≤ b b`−k
c < (c + 1)m ou cm ≤ b b`−k+1
c < (c + 1)m. Une autre
n
n
possibilité serait d’effectuer une recherche dichotomique, en comparant b b`−k
c ou b b`−k+1
c avec
{m, 2m, · · · , (b − 1)m} (voir l’exercice 3 de la feuille 2).
Ici encore, le calcul d’un produit cm, où 1 ≤ c ≤ b − 1, n’est pas une opération élémentaire
mais, comme b est fixé, la procédure mult permet son calcul en temps O(log m). De même, le
nombre total de produits cm à calculer est majoré uniquement en fonction de b. Il s’ensuit que c
peut être calculé en temps O(log m).
Dans le pseudoprogramme qui suit, on suppose disposer d’une procédure chif tel que, étant
donnés deux entiers m > 0 et 0 ≤ A ≤ mb − 1, chif(m, A) retourne le chiffre c tel que cm ≤ A <
(c + 1)m.
procédure div(n, m) (entrée : deux entiers naturels m et n avec m > 0 et écrits en base b ;
sortie : le couple (q, r) des deux entiers naturels q et r tels que n = qm + r et 0 ≤ r < m.)
variables locales : i, k, `, N (entier naturels), c (chiffre), Q (résultat intermédiaire)
si n < m, retourner (0, n),
sinon, k = blogb mc + 1, ` = blogb nc + 1,
si n ≥ mb`−k , i ← ` − k,
sinon, i ← ` − k − 1,
finsi
N ← n, Q ← 0,
tantque i ≥ 0,
Q ← Q + chif(m, bN/bi c)bi , N ← N − chif(m, bN/bi c)mbi , i ← i − 1,
fintantque
retourner(Q, N ),
finsi
La preuve de l’algorithme consiste à remarquer que, à chaque étape, on a n = Qm + N , et
que à la fin on a 0 ≤ N < m.
On note que, à chaque étape, on a N < mbi+1 , ce qui implique que bN/bi c ≤ mb − 1, et on
a le droit d’appliquer chif. La complexité est gouvernée par le nombre de fois que l’on applique
19
chif, ce qui à peu près ` − k ≈ logb (n/m). Puisque chif a une complexité dans O(log m)
et la multiplication chif(m, bN/bi c)mbi est la multiplication de m par un chiffre puis par une
puissance de b, la complexité de la mise à jour de Q et de N appartient à O(log m). Il s’ensuit que
la complexité de div appartient à O(log m log (n/m)).
Calcul du pgcd de deux entiers
Soient encore m, n deux entiers naturels. Notre premier but est d’estimer la complexité du
calcul du pgcd de m et de n à l’aide de divisions euclidiennes successives. On supposera que n ≥ m
(dans le cas contraire, on interchange m et n). Le cas m = 0 étant trivial, on supposera également
que m ≥ 1.
Rappelons que l’algorithme se décrit ainsi : on pose r−1 = n, r0 = m. Les suites qi (i ≥ 0) et
ri (i ≥ 1) sont alors définies récursivement par r−1 = q0 r0 + r1 et 0 ≤ r1 < r0 , puis, si ri 6= 0, par
ri−1 = qi ri + ri+1 et 0 ≤ ri+1 < ri . On a alors r0 > r1 > · · · > ri > · · · et, les ri étant des entiers
naturels, il existe donc un indice, que nous noterons k(m, n) (ou tout simplement k si aucune
confusion n’est à craindre), tel que rk−1 6= 0 mais rk = 0. À ce stade la suite s’arrête et rk−1 est
le pgcd de m et de n, que nous noterons pgcd(m, n).
Une première question est d’estimer k(m, n) en fonction de (m, n). Pour cela, on remarque
d’abord que
ri−1 = qi ri + ri+1 ≥ ri + ri+1 quelque soit i,
car qi ≥ 1. Cela suggère comparer la suite (ri ) avec une suite (si ) vérifiant si−1 = si +si+1 pour tout
i ∈ {0, 1, . . . , k − 1} et sk−1 = 1, sk = 0. Une telle suite est déterminée par les dernières conditions
sk = 0, sk−1 = 1, qui entraı̂ne que sk−2 = sk−1 +sk = 1+0 = 1, puis sk−3 = sk−2 +sk−1 = 1+1 = 2,
puis sk−4 = 2 + 1 = 3, sk−5 = 3 + 2 = 5 et ainsi de suite.
Autrement dit, sk , sk−1 , sk−2 , . . ., s0 est le début de la suite de Fibonacci (Fi )i≥1 définie
par F0 = 0, F1 = 1 et par Fi+2 = Fi+1 + Fi pour tout i ≥ 2. Elle commence par 0, 1, 1, 2, 3, 5, 8,
13, 21, 34, 55, 89, 144, 233, . . . . Elle est strictement croissante à partir du terme F1 .
La proposition suivante est donc une conséquence immédiate de la discussion précédente.
Proposition. Si k = k(m, n), alors m ≥ Fk .
Démonstration. En effet, avec les notations qui viennent d’être introduites, on a successivement
rk = sk = 0 = F0 , rk−1 ≥ sk−1 = 1 = F1 , rk−2 ≥ sk−2 = F2 puis, en général, rk−i ≥ sk−i = Fi pour
tout i ∈ {0, 1, . . . , k} et donc en particulier m = r0 ≥ s0 = Fk .
Afin d’estimer k(m, n), il suffit donc de savoir estimer les nombre de Fibonacci Fk .
Proposition. Soit
√
5+1
= 1.6180339887498948482 . . .
2
le nombre d’or. Alors pour tout k ≥ 0, on a
φ=
1 (−1)k−1 Fk = √ φk +
.
φk
5
Le résultat peut se vérifier par récurrence sur k ou mieux, en l’interprétant comme un cas
particulier de la résolution de suites récurrentes linéaires à coefficients constants. En effet, on sait
20
que si p et q sont deux complexes, alors toute suite vérifiant une relation de récurrence de la
forme un+1 = pun + qun−1 est de la forme un = Aθn + Bψ n , où θ et ψ sont les racines (supposées
distinctes et au moins une entre elles non-nulle) du polynôme x2 − px − q, et A et B sont des
constantes, qui sont déterminées par les valeurs de u0 et de u1 par exemple. (Si x2 − px − q a une
racine double θ 6= 0, alors la suite est de la forme un = (An + B)θn , où A et B sont encore des
constantes.)
Théorème. Il existe des constantes C > 0 et D telles que k(m, n) ≤ C log m + D quelque soit
m ≥ 1 et quelque soit n ≥ m.
k−1
Démonstration. Puisque φ > 1, on a | (−1)
φk
| ≤ 1 pour tout k ≥ 0 et donc
1
Fk ≥ √ φk − 1
5
pour tout k ≥ 0. Il s’ensuit que si k = k(m, n), alors m ≥ Fk ≥ √15 (φk − 1). Le théorème en
découle en prenant les logarithmes et après un peu de simplification.
Théorème. La complexité
du calcul du pgcd de deux entiers m et n avec 0 < m ≤ n appartient
n
.
à O (log m)2 + log m log m
Démonstration. Soit k = k(m, n). D’après notre étude de la division euclidienne avec reste,
chaque étape ri−1 = ri qi + ri+1 a une complexité dans O(log ri log ri−1
). La complexité totale
ri
appartient donc à
k−1
X
ri−1 O
.
log ri log
ri
i=0
(∗)
n
Ici, le terme avec i = 0 appartient à O(log m log m
) car r−1 = n et r0 = m. L’étude de la somme
k−1
X
log ri log
i=1
ri−1
ri
c pour tout i, ce qui entraı̂ne que ri−1
≤ qi +1
peut être effectuée ainsi. Tout d’abord, on a qi = b ri−1
ri
ri
ri−1
et donc que log ri ≤ log (qi + 1) ce qui est majoré par log qi + 1 comme en voit en appliquant le
théorème des accroissements finis à la fonction x 7→ log x sur l’intervalle [qi , qi + 1]. D’autre part,
ri est majoré par m lorsque i ≥ 0. Il s’ensuit que log ri ≤ log m et donc
k−1
X
i=1
k−1
k−1
X
X
ri−1
log ri log
≤ log m
(log qi + 1) = log m
log qi + (k − 1) log m.
ri
i=1
i=1
On sait déjà que k ∈ O(log m). Afin de conclure, il suffit donc de démontrer que
log m, ce qui est une conséquence du lemme suivant.
Q
Lemme. On a k−1
i=1 qi ≤ m.
Pk−1
i=1
log qi ≤
Démonstration du lemme. On a rk−2 = rk−1 qk−1 ≥ qk−1 car rk−1 est un entier naturel non
nul. Ensuite rk−3 = rk−2 qk−2 + rk−1 ≥ qk−2 qk−1 et doncQrk−4 = rk−3 qk−3 + rk−2 ≥ qk−3 qk−2 qk−1 .
En remontant ainsi, on
trouve successivement rk−j ≥ j−1
i=1 qi pour j = 1, 2, . . ., k et donc, en
Qk−1
particulier, m = r0 ≥ i=1 qi .
Remarque. Nous avons donc majoré le nombre k de divisions euclidiennes avec reste nécessaires
pour calculer le pgcd de m et de n lorsque n ≥ m ≥ 1 par C log m + D pour certaines constantes
21
C > 0 et D. On peut se demander si, dans le pire des cas, il faut effectivement Ω(log m) divisions.
La réponse est oui, et un exemple est fourni par le cas des nombres de Fibonacci m = F` et
n = F`+1 . Remarquons que si i ≥ 3, alors Fi+1 < 2Fi , comme on le voit par récurrence sur i. On
en tire que le quotient de la division euclidienne avec reste de Fi+1 par Fi est 1 et le reste est donc
Fi+1 − Fi = Fi−1 . Il s’ensuit que, si ` ≥ 3, alors qi = 1 et que ri = F`−i pour tout i ≤ ` − 2. Puisque
F2 = 1, le dernier reste non-nul est F2 = r`−2 et on a donc k(F` , F`+1 ) = ` − 1. Puisque F` ∼ √15 φ`
lorsque ` → +∞, on voit bien que dans ce cas le nombre de divisions nécessaires appartient à
Ω(log m).
L’équation de Bézout et l’algorithme d’Euclide étendu
Passons maintenant à l’étude du calcul d’une solution (u, v) de l’identité de Bézout un +
mv = d, où d = pgcd(m, n). Cela peut se faire en remontant le calcul des ri et des qi . Tout
d’abord, on a d = rk−1 et donc rk−3 − qk−2 rk−2 = d. En substituant rk−2 = rk−4 − qk−3 rk−3
dans cette équation, on obtient une relation de la forme uk−4 rk−4 + vk−3 rk−3 = d. De même, en
substituant rk−3 = rk−5 − qk−4 rk−4 on obtient une relation de la forme uk−5 rk−5 + vk−4 rk−4 = d.
En répétant, on arrive à une relation de la forme ur−1 + vr0 = d comme voulu.
C’est une méthode que l’on rencontre très souvent dans les cours d’arithmétique en licence.
Mais, présentée ainsi, elle a l’inconvient de nécessiter la garde en mémoire de toutes les étapes
intermédiaires.
L’algorithme d’Euclide étendu définit inductivement des suites (si ) et (ti ) en même temps
que les suites (qi ) et (ri ) de telle manière que à la fin de l’algorithme, u = si et v = ti sont des
solutions de un + vm = d. En voici un pseudoprogramme.
procédure EE(n, m) (entrée : n et m deux entiers naturels tels que n ≥ m ≥ 1 ; sortie :
(u, v, d) ∈ Z2 × N∗ tel que un + vm = d)
variables locales: i (indice), ri , qi , si , ti (entiers)
r−1 ← n, r0 ← m, s−1 ← 1, s0 ← 0, t0 ← 1, t−1 ← 0, i ← 0,
tantque ri 6= 0,
qi ←quo(ri−1 , ri ), ri+1 ← ri−1 − qi ri , si+1 ← si−1 − qi si , ti+1 ← ti−1 − qi ti , i ← i + 1,
fintantque
retourner(si−1 , ti−1 , ri−1 )
Ici, le quotient quo(ri−1 , ri ) de la division euclidienne avec reste de ri−1 par ri est calculé à
l’aide de la procédure div(ri−1 , ri ) décrite plus haut. Cette procédure donne également le reste
ri+1 =rem(ri−1 , ri ) mais la redaction ri+1 ← ri−1 − qi ri permet de souligner la similarité entre les
rélations de récurrence satusfaites par les ri , les si et les ti .
La preuve de l’algorithme consiste à vérifier que si n + ti m = ri quelque soit i. C’est vrai
lorsque i = −1 et i = 0 d’après l’initialisation de s−1 , de s0 , de t−1 et de t0 . Si l’on sait que
si−1 n + ti−1 m = ri−1 et que si n + ti m = ri , alors on constate que
si+1 n + ti+1 m = (si−1 − qi si )n + (ti−1 − qi ti )m = si−1 n + ti−1 m − qi (si n + ti m) = ri−1 − qi ri = ri+1 .
En particulier, si k = k(m, n), on a sk−1 n + tk−1 m = rk−1 = d. Tel qu’il est présenté, l’algorithme
calcule également sk et tk vérifiant sk n + tk m = rk = 0, ce qui paraı̂t inutile. Mais on verra (voir
la feuille d’exercices 4) que si et ti sont premiers entre eux quelque soit la valeur de i, ce qui
démontre le corollaire suivant :
Corollaire. On a sk tk 6= 0, et
|tk |
|sk |
est l’écriture de
22
n
m
comme fraction réduite.
On montrera en exercice (voir également la feuille 4), que la solution (sk−1 , tk−1 ) trouvée par
l’algorithme EE est la même que celle obtenue par la méthode rencontrée en licence.
L’analyse de la complexité nécessite un peu de soin. À l’étape i, le calcul de qi et de ri
appartient toujours à O(log ri log ri−1
). Mais il faut y ajouter désormais le coût des calculs de si+1
ri
et de ti+1 , et pour cela il faut savoir majorer ces entiers.
Lemme. On reprend les notations qui précèdent.
On a les majorations
n
m
,
|ti | ≤
|si | ≤
ri−1
ri−1
quelque soit i ∈ {0, 1, . . . , k}.
La démonstration de ce lemme est proposée en exercice (voir l’Exercice 2 de la feuille 4).
Lorsque i = 0, la boucle calcule (q0 , r1 , s1 , t1 ). Ici, la complexité du calcul de q0 et de r0
n
appartient à O(log m log m
), comme déjà expliqué. Mais s1 = 1 et t1 = −q0 et donc le calcul de
s1 et de t1 n’ajoute pas à la complexité.
Lorsque i ≥ 1, la complexité du calcul de si+1 comme si−1 − qi si appartient donc à l’ensemble
O(max(log |si−1 |, log qi log |si |)).
D’après le Lemme, on a |si−1 | ≤ m et |si | ≤ m : on peut donc majorer max(log |si−1 |, log qi log |si |)
par max(log m, log qi log m) puis par (log qi + 1) log m. Par conséquent, la contribution du calcul
des si appartient à
k−1
X
O
(log qi + 1) log m ⊆ O((log m)2 )
i=1
Qk−1
car on a vu précédemment que i=1 qi ≤ m.
Par un argument semblable, lorsque i ≥ 1, le calcul de ti+1 comme ti−1 − qi ti a un coût
appartenant à O((log qi + 1) log n). On en tire que la complexité du calcul de l’ensemble des ti
appartient à
k−1
X
O
(log qi + 1) log n ⊆ O((log m log n)).
i=1
Puisque n ≥ m et n ≥
n
,
m
le résultat suivant est une conséquence de ce qui précède.
Théorème. L’algorithme d’Euclide étendu EE qui calcule une solution de l’équation de Bézout
um + vn = d, d = pgcd(m, n), (u, v) ∈ Z2 a une complexité appartenant à O(log m log n).
L’ensemble O(log m log n) étant symétrique en m et en n, ce résultat est également valable
lorsque n ≤ m.
L’arithmétique dans le corps des rationnels
n
Tout nombre rationnel s’écrit de façon unique sous la forme m
avec n ∈ Z et m ≥ 1 premiers
n
entre eux. (En particulier, m = 1 lorsque n = 0.) On identifie m avec le couple d’entiers (n, m).
Si plus généralement (n, m) appartient à Z2 et m et n sont écrites en base b, une mesure de la
complexité de (n, m) est la somme du nombre de chiffres Cb (n) + Cb (m) de m et de n en base b,
soit logb |n| + 1 + logb |m| + 1 lorsque mn 6= 0.
Plus généralement, si on fixe une norme ||.|| sur R2 , on peut mesurer la complexité de (n, m)
par ||(Cb (n), Cb (m))|| lorsque mn 6= 0. Puisque toutes les normes sur R2 sont équivalentes, on se
23
rend compte très rapidement que le choix de la norme est peu importante dans les questions de
complexité.
n
avec n et m premiers entre eux, on appelle parfois ||(log |n|, log m)||
Si α ∈ Q× , α = m
la hauteur (logarithmique) de α associée à ||.||, et on la note h||.|| (α). Il est commode de poser
h||.|| (0) = 0. Le fait que toutes les normes soient équivalentes implique que Θ(h||.|| ) est indépendante
de la norme choisie. On écrira donc h à la place de h||.|| si le choix de la norme est claire, ou si ce
choix est immatériel.
Les opérations de l’arithmétique élémentaire se réduisent à celles sur les entiers grâce aux
formules
n −1 m
n
q
np ± mq
nq
nq
± =
,
=
,
= ,
m p
mp
mp
mp
m
n
la dernière formule n’étant valable que lorsque m 6= 0. Leur complexité est facilement mesurée en
n
termes de h(α) et de h(β), où α = m
et β = pq .
Considérons par exemple le cas de l’addition. En général, il y a trois multiplications (np,
mq, mp) à effectuer, puis une addition (np + mq) et, enfin, la simplification du numérateur et
du dénominateur, ce qui nécessite le calcul de leur pgcd, puis la division du numérateur et du
dénominateur par ce pgcd. Les trois multiplications ont des complexités appartenant respectivement à O(log n log p), à O(log m log q) et à O(log m log p), qui sont tous des sous-ensembles
de O(h(α)h(β). La complexité de l’addition np + mq appartient ègalement à cet ensemble. Par
contre, la complexité du calcul du pgcd de np + mq et de mp appartient, dans le pire des cas, à
O((max(h(α), h(β))2 ).
Par un calcul semblable mais plus simple, on voit que la complexité de la multiplication appartient également à O((max(h(α), h(β))2 ). Par contre, le calcul de 1/α est une opération élémentaire :
il suffit d’échanger m et n et rappeler que pgcd(m, n) = pgcd(n, m).
On remarque donc une différence fondamentale par rapport aux opérations arithmétiques
classiques dans Z. L’addition a une complexité appartenant à O((max(h(α), h(β))2 ) alors que,
lorsque α, β ∈ Z, la complexité de l’addition appartient à O(max(h(α), h(β)). Concrètement, cela
signifie que le nombre de chiffres du numérateur et du dénominateur augmente rapidement lorsque
on effectue des additions successives. Par exemple, les dénominateurs des rationnels α1 , α2 , . . ., αn
sont premiers entre eux deux-à-deux, le dénominateur de α1 + α2 + · · · + αn est le produit de ceux
des αi . Cela a comme conséquence que la complexité des calculs avec des rationnels ont tendance
à augmenter très rapidement.
À titre d’exemple, la division euclidienne avec reste du polynôme x10 par x2 − 61 x + 15 donne
x10 = (x2 − 61 x + 15 )q(x) + r(x), où
7
6
5
q(x) = x8 + x6 − 31x
− 67x
+
180
1080
875501x
198059
r(x) = 1259712000 + 5248800000 .
781x4
32400
+
3193x3
194400
−
12151x2
5832000
−
127099x
34992000
−
198059
,
1049760000
L’expérience montre que la situation est si grave que nous sommes amenés à donner le conseil
suivant, qui pourrait sembler un peu dramatique au premier regard :
Dans la mesure du possible, on évitera des calculs avec les nombres rationnels qui ne sont pas
les entiers.
Il y a toutefois un exemple où l’utilisation des rationnels peut être intéressante. Il s’agit de
l’utilisation de la méthode de Newton, par exemple pour calculer une racine carrée.
24
Rappelons le principe de la méthode de Newton. Soit f une fonction de classe C (2) sur un
intervalle ouvert I. On suppose qu’il existe α ∈ I tel que f (α) = 0 mais f 0 (α) 6= 0. On peut
montrer que si x ∈ I est suffisamment proche à α, alors la suite (xn ) définie par x0 = x et
n)
xn+1 = xn − ff0(x
converge vers α. En outre, cette convergence est quadratique, dans le sens qu’il
(xn )
existe une constante C > 0 telle que |xn+1 − α| ≤ C|xn − α|2 pour tout n assez grand. Cela signifie,
grosso modo, que le nombre de chiffres décimaux corrects de l’approximation xn de α double à
chaque itération.
Supposons par exemple que f est un polynôme à coefficients rationnels. Si x ∈ Q, alors xn ∈ Q
pour tout n et le calcul de le suite (xn ) appartient au domaine du calcul exact. En prenant pour
f le polynôme x2 − a, avec a ∈ Q∗+ , par
√ exemple, on obtient une méthode de calcul très efficace
d’une valeur approchée rationnelle de a.
√
Cette idée peut être utilisée, par exemple, pour calculer la partie entière de n lorsque n est
un entier naturel. Lorsque n est très grand, cette procédure
√ sera beaucoup plus rapide qu’une
procédure dichotomique, où on détermine k tel que bk ≤ n < bk+1 (n étant écrit en base b),
puis on élève au carré successivement bk , bk + bk−1 , bk + 2bk−1 , jusqu’à ce qu’on trouve le chiffre
ck−1 tel que (bk + ck−1 bk−1 )2 ≤ n < (bk + (ck−1 + 1)bk−1 )2 , puis on élève au carré successivement
bk + ck−1 bk−1 , bk + ck−1 bk−1 + bk−2 , bk + ck−1 bk−1 + 2bk−2 jusqu’à ce qu’on trouve le chiffre ck−2 tel
que (bk + ck−1 bk−1 + ck−2 bk−2 )2 ≤ n < (bk + ck−1 bk−1 + (ck−2 + 1)bk−2 )2 et ainsi de suite.
Par ailleurs, comme nous allons voir plus loin, l’idée derrière la méthode de Newton a d’autres
applications en calcul exact.
Calculs modulo un entier naturel.
La situation ici est beaucoup plus agréable que dans le corps des nombres rationnels. En fait,
nous verrons très vite que les calculs (mod m) ont des applications aux algorithmes utilisant des
entiers et même des nombres rationnels.
Notation. Si m ≥ 1 est un entier naturel, on note Zm l’anneau Z/mZ. Lorsque m = p, un
nombre premier, on le notera souvent Fp . (On trouve également la notation Zp , mais cela peut
semer de la confusion.)
Si a ∈ Z, on note am (ou tout simplement a si aucune confusion n’est à craindre) sa classe
dans Zm .
Si α ∈ Zm , on note α̃ ou (α)˜ l’unique représentant a ∈ Z de α qui vérifie 0 ≤ a < m.
On identifie α avec α̃, dans le sens qu’on considère que α soit connu si et seulement si α̃ soit
connu, et le passage entre α et α̃ est considéré comme une opération élémentaire.
Par conséquent, la détermination de la classe (mod m) d’un entier quelconque a n’est pas une
opération élémentaire. Sa complexité est celle du calcul de α̃, où a = α. Or, α̃ est le reste de la
division de a par m ; la complexité de la détermination de α est donc celle du calcul de ce reste,
soit O(log m log |a|
).
m
Soient α, β ∈ Zm . Alors α̃ ± β̃ 6= (α ± β)˜ en général, et le calcul de (α + β)˜ nécessite le
calcul du reste de la division de α̃ ± β̃ par m. On a 1 − m ≤ α̃ ± β̃ ≤ 2m − 1 et, comme l’addition
ou la soustraction de deux entiers a et b se fait en temps O(max(log |a|, log |b|)) et la division
euclidienne de a par m en temps O(log m log |a|
), on voit que le calcul de α ± β se fait en temps
m
O(log m) quelque soient les valeurs de α et de β.
Considérons de la même façon le calcul de αβ. Ici, 0 ≤ αβ ≤ (m − 1)2 et (αβ)˜ est le reste
après division par m d’un entier positif ne dépassant pas m2 . Le calcul de αβ a un coût dans
25
2
O((log m)2 ), alors que la division euclidienne a un coût dans O(log m log mm ) ce qui est encore égal
à O((log m)2 ).
Passons au calcul de α/β. Cela suppose que β soit inversible, c’est-à-dire qu’il existe γ ∈ Zm
tel que βγ = 1. Alors α/β = αγ et le calcul de α/β est réduit au calcul de γ puis du produit αγ.
Rappelons que β est inversible si et seulement si pgcd(β̃, m) = 1, ou encore si et seulement
si l’équation de Bézout uβ̃ + vm = 1 possède une solution (u, v) ∈ Z2 . Lorsque c’est le cas, on a
γ = u. Le calcul de u se fait avec l’algorithme d’Euclide étendu EE ; son temps de calcul est donc
dans O(log m log β̃) ⊆ O((log m)2 ). D’après l’Exercice 2 de la feuille 4, on sait que |u| < m. Par
conséquent, γ̃ = u si u ≥ 0 et γ̃ = u + m is u < 0. Le calcul de u + m est dans O(log m), donc
n’ajoute rien de significatif.
Par conséquent, le calcul de γ se fait en temps O((log m)2 ) et, d’après notre discussion du
calcul du produit, αγ se calcule encore en temps O((log m)2 ). Au total, donc, α/β se calcule en
temps O((log m)2 ).
Aux algorithmes d’addition, de soustraction, de multiplication et de division, il convient de
mentionner ici le calcul de puissances.
Afin de calculer αn , où n ≥ 1 est un entier, la méthode de carrés successifs et la plus
efficace. En voici le pseudoprogramme.
procédure puiss(α, n) (entrée : α ∈ Zm , n entier naturel ; sortie : αn )
variables locales : ` entier naturel, β, γ éléments de Zm
` ← n, β ← 1, γ ← α,
tantque ` > 0,
si ` pair, γ ← γ 2 , ` ← 2` ,
sinon, β ← βγ, γ ← γ 2 , ` ← `−1
,
2
finsi
fintantque
retourner β
Le nombre d’étapes est égal au nombre de chiffres de n écrit en base 2. À chaque étape, il y
a un plus deux multiplications à effectuer, qui se font en temps O((log m)2 ). Il s’agit donc d’un
algorithme à complexité appartenant à O((log m)2 log n) ; il est donc beaucoup plus rapide que
l’algorithme naı̈f , qui calcule successivement α, α2 = αα, α3 = α2 α, . . ., αk+1 = αk α, . . .,
αn = αn−1 α qui a une complexité appartenant à O((log m)2 n).
Afin de prouver l’algorithme, il est utile de le généraliser un peu. Nous verrons que si, au lieu
d’initialiser β en 1, nous l’initialisons en un élément quelconque ζ de Zm , alors l’algorithme a pour
sortie ζαn et non αn .
Pour cela, on raisonne par récurrence sur n, le cas n = 0 étant clair. Supposons donc que
n ≥ 1. Si n est pair, on applique d’abord l’instruction si ` pair, γ ← γ 2 , ` ← 2` , avec ` = n et
γ = α. L’hypothèse de récurrence implique alors que la sortie de l’algorithme sera alors la même
n
que lorsque n est remplacé par n2 , α par α2 , et β par ζ, soit ζ(α2 ) 2 = ζαn . De même, lorsque n
est impair, la sortie de l’algorithme sera la même que lorsque n est remplacé par n−1
, α par α2 et
2
n−1
β par αζ, soit αζ(α2 ) 2 = ζαn .
Rappelons pour mémoire le résultat suivant.
Théorème (appelé souvent théorème d’Euler). Soit α ∈ Zm un élément inversible. Alors
αφ(m) = 1,
26
où φ est la fonction indicatrice d’Euler, c’est-à-dire φ(m) est le nombre d’entiers k ∈ {0, 1, . . . , m−
1} premiers à m.
Si r dśigne le reste après division euclidienne de n par φ(m), alors αn = αr . Si donc φ(m) est
connu, et n est plus grand que φ(m), une méthode alternative de calculer αn serait de calculer r puis
de calculer αr . Puisque la complexité de la division euclidienne appartient à O(log n log φ(m) ⊆
O(log n log m), cela présente des avantages si n est grand par rapport à m.
Lorsque α est inversible, on a la formule 1/α = αφ(m)−1 . Elle permet de calculer 1/α comme
une puissance positive de α. Le temps de calcul appartient à O((log(m)2 φ(m)) en général, ce qui
n’est pas aventageux. Par contre, si l’on connaı̂t l’ordre e de α et s’il est relativement petit, le
calcul de 1/α comme αe−1 peut être relativement intéressant.
Malheureusement, on ne connaı̂t pas d’algorithme rapide de calcul de l’ordre de α en général.
Et de φ(m) non plus. Il y a une formule explicite pour φ(m), à savoir
Y
1
,
φ(m) = m
1−
p
p|m
le produit étant pris sur tous les nombres premiers p divisant m. Le calcul de φ(m) nécessite
donc une connaissance de l’ensemble des nombres premiers divisant m. Mais si p est un nombre
premier divisant m, alors l’exposant f de la puissance exacte de p divisant m est majoré par
logp m : si donc on connaı̂t l’ensemble des diviseurs premiers de m, il est facile de déterminer la
factorisation complète de m. Autrement dit, connaı̂tre φ(m) équivaut essentiellement à connaı̂tre
la factorisation de m. Mais nous ne connaissons pas d’algorithme de factorisation d’un entier m
dont la complexité appartient à O((log m)c ), quelque soit la valeur de c.
Quelques remarques sur les calculs dans les anneaux
Par anneau, on entendra toujours anneau commutatif unitaire. On écrit respectivement 0 ou
0A , 1 ou 1A pour les éléments zéro et l’unité. Jusqu’ici, nous nous limités aux calculs dans Z, dans
Q et dans les anneaux Zm = Z/mZ. Désormais, nous allons nous intéresser aux calculs dans des
anneaux plus généraux.
Soit donc A un anneau. Un premier problème est de comparer les temps de calculs dans
certains anneaux construits à partir de A avec les temps de calcul dans A. Si A est un anneau,
voici trois méthodes de construire un autre anneau à partir de A :
(i ) L’anneau (ou algèbre) des polynômes A[x], x une indéterminée ;
(ii ) Lorsque A est intègre, le corps de fractions de A, que nous noterons Fr(A).
(iii ) L’anneau quotient A/I, I étant un idéal sur A ;
On pourrait y a ajouter : l’anneau produit A × B, B étant un second anneau, ou Ad , (d ≥ 1),
ou encore Mn (A), l’algèbre des matrices carrées d’ordre n à coefficients dans A.
Par ailleurs, la construction du corps de fractions peut être généralisée ainsi, A étant toujours
supposé intègre. Une partie S ⊆ A est dite multiplicative si (a) 1 ∈ S, (b) si s, t ∈ S, alors st ∈ S.
L’anneau des fractions à dénominateurs dans S, noté S −1 A, est l’ensemble A × S quotienté par
la relation d’équivalence (a, s) ∼ (b, t) si et seulement si at = bs. La classe d’équivalence de (a, s)
sera notée a/s, as ou as−1 . On munit S −1 A des lois d’addition, de soustraction est de multiplication
suivantes :
a b
at + bs
+ =
,
s t
st
a b
at + bs
− =
,
s t
st
27
ab
ab
= .
st
st
L’élément 0 est la classe de (0, 1), l’unité est celle de (1, 1). La classe de (a, s) est inversible
si et seulement s’il elle contient un élément (b, t) tel que b ∈ S ; son inverse est alors la classe de
(t, b).
On obtient le corps de fractions de A en prenant pour S l’ensemble des éléments non-nuls de
A.
Lorsque A n’est pas intègre, la relation ∼ n’est plus une relation d’équivalence en général. On
la remplace alors par : (a, s) ∼ (b, t) si et seulement s’il existe u ∈ S tel que (at − bs)u = 0. Les
définitions de l’addition, de la soustraction et de la multiplication sont inchangées. Dans ce cours,
on ne considérera que le cas où A est intègre.
Grosso modo, les anneaux dans lesquels on sait programmer des calculs exacts sont ceux qui
peuvent être construits à partir de l’anneau Z par une suite finie de constructions de type (i), (ii )
(généralisé à l’anneau des fractions) et (iii ). Nous allons discuter cas-par-cas les problèmes posés
par les calculs de base dans ces anneaux, en supposant programmés les calculs de base dans A.
Dire que nous savons programmer les calculs de base dans A signifie que nous disposons de :
(∗) une ensemble S dont les éléments représentent les éléments de A. On dispose d’un algorithme testant si oui ou non deux éléments de S représenent le même élément de A. Parfois, S
contient un sous-ensemble R contenant un et un seul représentant de chaque élément de S, que
l’on convien d’appeler représentant distingué.
(∗∗) des programmes permettant le calcul de la somme, la différence et le produit de deux
éléments de A, dont les entrées et la sortie sont les représentants distingués appartenant à R.
Par exemple, si A = Z, on utilise comme représentation d’un élément n de A le couple
(ε, (ak−1 ak−2 · · · a0 )b ) où ε ∈ {−, 0, +} est le signe de n et (ak−1 ak−2 · · · a0 )b ) est l’écriture en base
b de |n|. Ici, cette représentation est unique, et R = S.
Si A = Zm , où m ≥ 1, on prend S = Z et R est l’ensemble des entiers compris entre O et
m − 1.
Lorsque A = Q, on prend S = Z × (Z \ {0}) et, si l’on suit les conventions du paragraphe
consacré au calculs avec des nombres rationnels, R est composé des couples (n, m) ∈ S avec m > 0
et pgcd(m, n) = 1.
Cette dernière construction se généralise aux anneaux de fractions S −1 A. Si S est un ensemble
de représentants des éléments de A et si T est un sous-ensemble de S représentant des éléments de
S, alors tout élément de S −1 A est représenté par un couple appartenant à S × T et les opérations
d’addition, de soustraction et de multiplication dans S −1 A revient à des opérations arithmétiques
dans A. Bien entendu, il faut disposer d’un algorithme testant si un élément de S appartient à T ,
ce qui sera le cas notamment lorsque S = A \ {0}. En particulier, si les opérations arithmétiques
de base dans A sont programmables, ceux dans le corps de fractions de A peuvent l’être aussi.
Calculs dans l’algèbre de polynômes A[x]
Nous nous limiterons au cas d’une indéterminée, qui est notée x. On note deg f le degré d’un
polynôme non nul f ∈ A[x] et on pose deg 0 = −∞. Un polynôme de degré d a donc d + 1
coefficients. On note A≤d [x] le A-module des polynômes de degré au plus d à coefficients dans A.
Nous mesurerons la complexité en termes du nombre d’additions ou de soustractions, le nombre
de multiplications dans A et de divisions par un élément inversible de A.
Si f , g ∈ A≤d [x], f ± g se calculent à l’aide d’au plus d + 1 additions ou soustractions dans A.
28
P
P
Considérons le cas de la multiplication. Si f = di=0 fi xi et si g = dj=0 gj xj , alors le coefficient
P
de xk dans f g est ki=0 fi gk−i . Si k ≤ d, son calcul nécessite donc k + 1 multiplications (calcul de
fi gk−i pour i ∈ {0, 1, . . . , k}) puis k additions. Sinon, on aPd + 1 ≤ k ≤ 2d
et il y a 2d − k + 1
P2d
d
multiplications et 2d − k additions. Il y a donc un total de k=0 (k + 1) + k=d+1 (2d − k + 1) =
P
P
2
(d + 1)2 multiplications et dk=0 k + 2d
k=d+1 (2d − k) = d additions.
Comme dans le cas de la multiplication des entiers relatifs, on peut se demander si on peut
faire mieux. À nouveau, la réponse est oui (voir plus loin).
En ce qui concerne la division par un élément inversible de A[x], on rappelle que f ∈ A[x] est
inversible si et seulement si f est constant et inversible dans A. Diviser par un élément inversible
de A[x] revient donc à diviser par un élément inversible de A.
Il convient de dire quelqus mots sur l’évaluation d’un polynôme en un élément de A. Si
l’on pose f (x) = f0 + f1 x + f2 x2 + · · · + fd xd et si on souhaite calculer f (a), où a ∈ A, on peut
bien évidemment calculer successivement a, a2 , a3 , . . ., ad puis les produits fk ak et enfin la somme
f0 + f1 a + f2 a2 + · · · + fd ad . Cela nécessite d − 1 multiplications pour calculer les puissances ak ,
2 ≤ k ≤ d puis encore d multiplications pour calculer les produits fk ak (1 ≤ k ≤ d) et enfin d
additions pour déterminer f (a).
Le schéma de Horner est nettement plus efficace. Définissons la séquence (φi )0≤i≤d d’éléments
de A par φ0 = fd et par φk = fd−k + φk−1 a lorsque 0 < k ≤ d. Alors
φ0 = fd ,
φ1 = fd−1 + fd a,
φ2 = fd−2 + fd−1 a + fd a2 ,
...
et à la fin on trouve
φd = f0 + f1 a + f2 a2 + · · · + fd−1 ad−1 + fd ad = f (a).
Cela nécessite seulement d multiplications et d additions et évite le stockage en mémoire de
résultats intermédiaires.
La division euclidienne avec reste existe elle aussi chez les polynômes :
Proposition. Soient f , g ∈ A[x] avec f 6= 0. On suppose que le coefficient directeur de f soit
inversible. Alors il existe un unique couple (q, r) ∈ A[x]2 tel que g = qf + r et deg r < deg f .
Démonstration. Si deg g < deg f , on prend q = 0 et r = g. C’est la seule possibilité, car si
(q, r) 6= (0, g) vérifie g = qf + r, alors forcément q 6= 0 et donc deg (qf ) = deg q + deg f ≥ deg f ,
d’où deg r = deg (g − qf ) = deg (qf ) ≥ deg q.
Supposons donc que deg g ≥ deg f . On écrit alors deg g = d et deg f = c. Il est clair
Pd que iq
(s’il existe)
est
de
degré
d
−
c.
Afin
de
montrer
l’existence
de
(q,
r),
on
écrit
donc
g
=
i=0 gi x ,
Pc
Pd−c
i
i
f = P
i=0 fi x , puis on cherche des coefficients qi et ri tels que si on pose q(x) =
i=0 qi x ,
c−1
r(x) = i=0 ri xi , alors g = qf + r. Explicitement, cette équation donne :
gd xd + gd−1 xd−1 +gd−2 xd−2 + · · · + gc xc + · · · = qd−c fc xd + (qd−c−1 fc + qd−c fc−1 )xd−1 +
+ (qd−c−2 fc + qd−c−1 fc−1 + qd−c−2 fc )xd−2 + · · ·
· · · + (q0 fc + q1 fc−1 + · · · + qc f0 )xc + termes de degré au plus c − 1.
La comparaison successive des coefficients de xd , xd−1 , xd−2 , . . ., xc donne gd = qd−c fc , gd−1 =
qd−c−1 fc + qd−c fc−1 , gd−2 = qd−c−2 fc + qd−c−1 fc−1 + qd−c−2 fc , . . ., gc = q0 fc + q1 fc−1 + · · · + qc f0 . Par
hypothèse, fc est inversible, et la première équation implique donc que qd−c = gd /fc . Les équations
suivantes déterminent successivement qd−c−1 , qd−c−2 , . . ., q0 . Le polynôme q est ainsi uniquement
déterminée et on a forcément r = g − qf .
29
Ici, la comparaison des coefficents de xi , (c ≤ i ≤ d), fait intervenir d − i + 1 multiplications
puis le calcul du membre droit de l’équation réarrangée qi−c = (gi −qi−c+1 fc−1 −qi−c+2 fc−2 −· · · )/fc
fait intervenir d − i soustractions et une division par l’élément inversible fc . EnP
prenant la somme
d
de
i
=
c
jusqu’à
i
=
d,
on
voit
que
pour
calculer
q
l’algorithme
a
besoin
de
i=c (d − i + 1) =
Pd−c+1
Pd
j = (d − c + 1)(d − c + 2)/2 multiplications, de i=c (d − i) = (d − c)(d − c + 1)/2 additions
j=1
ou soustractions et de d − c + 1 divisions par fc .
Corollaire. Dans la division euclidienne de g par f , où d = deg g ≥ deg f = c, le calcul de
q nécessite donc O((d − c + 1)2 ) opérations arithmétiques dans A. Le calcul de r comme g − qf
nécessite O((d − c)c) opérations arithmétiques dans A.
Groupe des éléments inversibles, idéaux, anneaux quotients
En règle général, nous aimerions allons maintenant aborder brièvement des questions liées au
groupe des éléments inversibles et d’appartenance ou non d’un élément à un idéal de l’anneau A.
Dans un premier temps, on pourra ajouter aux programmes (∗) et (∗∗) déjà mentionnés les
programmes suivants :
(∗∗∗) un programme testant si un élément a ∈ A est inversible ou non et, dans le cas affirmatif,
de calculer 1/a, l’entrée et la sortie utilisant les représentants dans l’ensemble S (ou, le cas échéant,
l’ensemble R).
(∗∗∗∗) un programme testant si, étant donné un élément a ∈ A et un idéal I de A, l’élément
a appartient à I ou non.
Remarquons que (∗∗∗∗) permet, comme cas particulier, de tester la divisbilité exacte d’un
élément par un autre : étant donné a ∈ A et b ∈ A, on veut savoir s’il existe c ∈ A tel que a = bc.
En effet, cela revient à tester si a appartient à l’idéal engendré par b.
Le plus souvent, l’idéal I est défini par une famille de générateurs GI , et tester is a appartient
à I revient à déterminer s’il existe n ≥ 1, b1 , b2 , . . ., bn ∈ GI et c1 , c2 , . . ., cn ∈ A tels que
a = b1 c 1 + b2 c 2 + · · · + bn c n .
Par ailleurs, le programme (∗∗∗∗) permet les calculs dans l’anneau quotient A/I. Un élément
α de A/I est une classe a + I = {a + i | i ∈ I}, où a est un élément de A. Ainsi, deux éléments a
et b sont dans la même classe modulo I si et seulement si a − b ∈ I. On peut alors utiliser comme
ensemble de représentants le même ensemble que pour les calculs dans A.
Soit par exemple A un anneau. Soit f (x) ∈ A[x] un polynôme unitaire (ou au moins à coefficient dominant inversible) de degré d ≥ 1 et soit I l’idéal de A[x] engendré par f (x). Soit
α ∈ A[x]/I et soit g ∈ A[x] un élément de α. Alors le reste r(x) de la division euclidienne de g(x)
par f (x) appartient également à α. On en tire que toute classe de A[x]/I est représentée par une
unique polynôme de degré au plus d − 1. L’addition et la soustraction dans A[x]/I s’effectue donc
à l’aode de l’addition et la soustraction de polynômes de degrés au plus d − 1. Pour calculer le
représentant d’un produit, il est en général nécessaire de prendre le reste après division euclidienne
par f (x) du produit des deux polynômes.
Ces remarques s’appliquent notamment aux corps de nombres, c’est-à-dire aux corps K qui
sont des Q-espaces vectoriels de dimension finie d ≥ 1. On sait que si K est un corps de nombres,
il existe un polynôme irréductible f (x) ∈ Q[x] de degré d tel que K soit isomorphe à Q[x]/(f (x)).
Alors tout élément de K est représenté par un unique polynôme de degré au plus d − 1 et on peut
effectuer des calculs dans K par les méthodes qui viennent d’être expliquées.
30
De même, si p est un nombre premier, si Fp désigne le corps à p éléments et si f (x) ∈ Fp [x],
on peut effectuer des calculs dans l’anneau quotient Fp [x]/(f (x)). En particulier, tous les corps
finis sont décrits de cette manière, ce qui permet d’effectuer les calcus dans ces corps, ce qui a
des applications importantes de cryptographie.
Le problème du calcul du groupe des éléments inversibles A× de A est, en général, beaucoup
plus difficile. Mentionnons pour la culture générale le résultat suivant, qui est un cas spécial d’un
théorème de Dirichlet.
Théorème. Soit f (x) ∈ Z[x] un polynôme unitaire, irréductible en tant qu’élément de Q[x]
et soit A = Z[x]/I. Notons respectivement r et s le nombre de racines réelles de f et le nombre
de couples de racines conjuguées complexes non réelles de f (x). Alors il existe un groupe cyclique
fini C tel que le groupe A× est isomorphe au produit direct C × Zr+s−1 .
La démonstration du théorème (et encore plus la description d’un algorithme calculant A× )
est hors de portée d’un cours de M1.
En ce qui concerne les calculs dans les anneaux quotients, le cas le plus fréquent est celui d’un
quotient d’une algèbre de polynômes. Le cas de A[x]/(f (x)), où f (x) est un polynôme unitaire,
a déjà été traité. Le cas où f n’est pas unitaire peut souvent être ramené au précédent en remplaçant A par l’anneau de fractions S −1 A, où S est l’ensemble des puissances {fdn }n≥0 , où fd est
le coefficient directeur de f .
Par contre, lorsque n ≥ 2, le cas d’un quotient de A[x1 , x2 , . . . , xn ]/I nécessite la notion de
base de Groebner, dont l’étude à nouveau dépasse les limites de ce cours.
Le théorème chinois
Dans le paragraphe précédent, nous avons discuté quelques cas de passage d’un anneau A à un
anneau quotient A/I. Par extension, on peut donc passer de A à plusieurs anneaux quotient puis à
leur produit cartésien. Le théorème chinois permet d’aller en sens inverse : utiliser des algorithmes
dans des anneaux quotients pour calculer un élément de A.
Dans le cas où A = Z le principe est simple et est justifié par le lemme suivant :
Lemme. Soit a ∈ Z, soit B ∈ R+ et soit m un entier. Si |a| ≤
uniquement déterminé par sa classe modulo m.
B
2
et si m > B, alors a est
Démonstration. En effet, si b est un second entier tel que |b| ≤ B2 , alors |a − b| ≤ B. Et si
encore a ≡ b (mod m), alors ou bien a = b ou bien |a − b| ≥ m. Mais comme m > B, la deuxième
possibilité est incompatible avec le l’inégalit |a − b| ≤ B. Donc a = b.
Ce lemme est utilisé de la manière suivante. Supposons on cherche un algorithme dont la sortie
est un entier a, disons, et on connaı̂t : (i ) un majorant B de 2|a| et (ii ) un la valeur de a (mod m),
m étant un entier. Alors on connaı̂t a.
Les calculs (mod m) peuvent être avantageux si les étapes de l’algorithme font intervenir des
entiers a priori beaucoup plus grands que m, et les calculs (mod m) suffisent.
Une extension de ce principe est d’utiliser une factorisation de m. Si on sait que m =
m1 m2 · · · mk avec les entiers mi deux-à-deux premiers entre eux, alors une classe (mod m) est
uniquement déterminée par des classes (mod mi ) pour tout 1 ≤ i ≤ k. C’est un cas particulier du
théorème chinois.
En pratique, cela ne signifie pas qu’il faut savoir factoriser m, car il ne joue qu’un rôle de
majorant ; on peut donc agrandir m si besoin. Par exemple, on peut calculer les produits des
31
premiers nombres premiers (2 × 3 × 5 × 7 × · · · ) jusqu’à ce que ce produit dépasse m, puis
remplacer m par ce produit. Les calculs (mod m) peuvent alors être remplacé par des calculs
(mod 2), (mod 3), (mod 5), (mod 7), . . ..
Théorème. Il existe x0 > 0 tel que pour tout x ≥ x0 assez grand, on ait
X
1
x≤
log p ≤ 2x log 2.
2
p premier
p≤x
Une démonstration est proposée dans l’Exercice 4 de la feuille 6. On pourra aussi consulter G.
Tenenbaum, Introduction à la théorie analytique et probabiliste des nombres, Belin, 2008, pages
29–30.
La constante x0 peut être calculée explicitement. Voici un autre résultat concernant la distribution des nombres premiers qui sera utilisé par la suite dans l’estimation des complexités :
Théorème (postulat de Bertrand). Étant donné x ≥ 2, il existe un nombre premier p tel que
x < p ≤ 2x.
Si x ≥ x0 , ce résultat découle du théorème précédent. En effet, on a alors
X
X
log p ≥ x
et
log p ≤ 2x log 2.
p≤2x
p≤x
P
Puisque log 2 < 1, on conclut que x<p≤2x log p > 0, ce qui n’est possible que s’il existe un nombre
premier dans l’intervalle ]x, 2x]. Le cas des petites valeurs de x se fait par un calcul explicite. Voir
à nouveau l’Exercice 4 de la feuille 6.
Nous appliquerons ces idées dans le paragraphe suivant pour calculer des déterminants de
matrices à coefficients entiers. Pour l’instant, nous nous contenterons d’énoncer et de démontrer le
théorème chinois dans un cadre plus général, car il sert aussi pour les calculs avec des polynômes.
Deux idéaux I et J de A sont dits comaximaux si I + J = A (c’est-à-dire s’il existe i ∈ I,
j ∈ J tels que i + j = 1.
Théorème. Soit A un anneau et soit I1 , I2 , . . ., Ik une famille finie d’idéaux comaximaux de
A. Alors l’homomorphisme canonique
π : A → A/I1 × A/I2 × · · · × A/Ik
est surjectif, et son noyau est I1 ∩ I2 ∩ · · · ∩ Ik .
Démonstration. Ici, π est le produit cartésien des homomorphismes canoniques A → A/Ir
(1 ≤ r ≤ k). Puisque le noyau de l’homomorphisme canonique A → A/Ir est Ir , il est clair que le
noyau de π est I1 ∩ I2 ∩ · · · ∩ Ik .
Montrons donc la surjectivité. Soient r, s deux éléments distincts de {1, 2, . . . , k}.
Q La condition
Ir + Is = A signifie qu’il existe ir,s ∈QIr , is,r ∈ Is tels que ir,s + is,r = 1. Posons ir = s6=r is,r . Alors
ir ∈ Is pour tout s 6= r et ir − 1 = s6=r (1 − ir,s ) − 1 ∈ Ir . Il s’ensuit que si (a1 , a2 , . . . , ak ) ∈ Ak ,
alors (a1 + I1 , a2 + I2 , . . . ak + Ik ) = π(a1 i1 + a2 i2 + · · · + ak ik ).
La démonstration fournit explicitement une valeur a ∈ A telle que π(a) = (a1 + I1 , a2 +
I2 , . . . , ak + Ik ), sous reserve de connaı̂tre des solutions ir,s , is,r de ir,s + is,r = 1. Lorsque A = Z,
dire que deux idéaux mZ et nZ sont comaximaux équivaut à dire que les entiers m et n sont
premiers entre eux ; la solution de l’équation i + j = 1 avec i ∈ mZ, j ∈ nZ revient alors à la
32
solution de l’équation de Bézout um + vn = 1, donc à une application de l’algorithme d’Euclide
étendu.
Estimons le nombre d’opérations dans A qui sont nécessaires pour exécuter un algorithme
implémentant la preuve, en supposant connus les éléments ir,s lorsque s 6= r. Alors ir se calcule
avec k − 1 multiplications et alors la détermination de a = a1 i1 + a2 i2 + · · · + ak ik nécessite encore
k multiplications et k − 1 additions, d’où un total de k − 1 additions et 2k − 1 multiplications.
Ce calcul suppose que l’on connaı̂t des solutions ir,s ∈ Ir de l’équation ir,s + is,r = 1. Leur
détermination dépendent évidemment de l’anneau A.
Lorsque A = Z, on peut estimer la taille des entiers ir construits au cours de la démonstration.
Notons pour cela mr le générateur positif de l’idéal Ir . On sait que chacune des équations de Bézout
ur,s mr + us,r ms = 1, 1 ≤ r < s ≤ k a une solution (ur,s , us,r ) avec |ur,s | < ms et |us,r | < mr . On
pose alors ir,s = uQ
ms , ce qui implique que |ir,sQ
| ≤ mr ms et |is,r | ≤ mr ms . Il
r,s mr et is,r = us,rQ
k
k−2
s’ensuit que |ir | = s6=r |ir,s | ≤ mk−1
m
=
m
m,
où
m
=
s
r
r
s6=r
r=1 mr est le module produit.
Puisque |ar | ≤ mr quelque soit r, on en tire que
|a| ≤
k
X
|ar ir | ≤
r=1
k
X
m)
mr (mk−2
r
=m
k
X
mrk−1 .
r=1
r=1
Supposons par exemple que tous les mr soient d’environ la même grandeur. Leur produit étant
égal à m, cela signifie que chacun des mr est d’une grandeur comparable avec m1/k . On en tire que
1
la majoration de |a| est comparable avec km2− k . Mais si les grandeurs des mr sont plus dispersées,
la majoration sera moins bonne.
Voici une autre construction de a qui peut être Q
utilisée lorsque A est un anneau principal.
Notons alors mr un générateur de Ir et posons m = kr=1 mr . Lorsque r ≤ s, la condition que Ir
et Is soient comaximaux signifie que mr et ms sont premiers entre eux. Il s’ensuit que mr et mmr
sont premiers entre eux quelque soit r ∈ {1, 2, . . . , k}. L’équation de Bézout ur mr + vr mmr = 1 a
donc une solution (ur , vr ) et on constate alors que si l’on pose
m
m
m
+ a2 v2
+ · · · + ak vk
,
m1
m2
mk
Q
alors a ≡ ar vr mmr ≡ ar (mod Ir ) car mms = t6=s mt est divisible par mr lorsque s 6= r et premier
à mr lorsque s = r, et vr mmr ≡ 1 (mod Ir ). Nous noterons CHIN(m1 , m2 , . . . , mk ; a1 , a2 , . . . , ak ) la
procédure ainsi obtenue, dont la sortie est l’entier rem(a, m).
Cherchons donc à majorer |a|. D’après notre étude de l’équation de Bézout, on sait calculer
une solution (ur , vr ) avec |vr | < mr . Si les valeurs ar vérifient |ar | ≤ mr pour tout r, alors on
trouve que
a = a1 v 1
|a| ≤ |a1 ||v1 |
m
m
m
+ |a2 ||v2 |
+ · · · + |ak ||vk |
≤ m(m1 + m2 + · · · + mk ) ≤ km2 .
m1
m2
mk
Le cas k = 2 est évidemment particulièrement important, et le cas général peut être réduit à
celui-ci par récurrence. Dans ce cas, les deux méthodes fournissent la même valeur de a.
Proposition. Soit k ≥ 2 et soient mr , (1 ≤ r ≤ k), une famille d’entiers naturels deux-àdeux premiers entre eux. Posons m = m1 m2 · · · mk . Soit (a1 , a2 , . . . , ak ) ∈ Zk . Si |ar | ≤ mr pour
tout r ∈ {1, 2, . . . , k}, alors la complexité de la procédure CHIN(m1 , m2 , . . . , mk ; a1 , a2 , . . . , ak )
appartient à O(k(log m)2 ).
33
Démonstration. Le calcul de m a une complexité appartenant à O(k(log m)2 ). Une fois m
connue, il faut calculer les k quotients mmr : la complexité du calcul de chacun des ses quotients
appartient à O(log mmr log mr ) ⊆ O((log m)2 ) et la complexité du calcul des k quotients appartient
à O(k(log m)2 ). Ensuite, le calcul de chacun des couples (ur , vr ), 1 ≤ r ≤ k, solutions de l’équation
de Bézout ur m + vr mmr = 1 a une complexité appartenant à O((log mmr )(log mr )) ⊆ O((log m)2 ). La
complexité du calcul de l’ensemble des k couples (ur , vr ) appartient donc encore à O(k(log m)2 ).
Ensuite, le calcul de a s’effectue à l’aide de 2k multiplications et k−1 additions de nombres tous
majorés en valeur absolue par m ; ce calcul se fait donc en complexité appartenant à O(k(log m)2 ).
Le résultat n’est pas forcément réduit (mod m), mais la division euclidienne de a par m qui
2
détermine rem(a, m) a une complexité appartenant à O((log km
)(log m)), ce qui ne modifie pas
m
la complexité totale.
Quelques algorithmes de base en algèbre linéaire
Avant d’étudier une première application du théorème chinois au calcul du déterminant d’une
matrice à ceofficients entiers, nous étudierons rapidement dans ce paragraphe quelques algorithmes
de base en algèbre linéaire. Soit donc K un corps commutatif : si d, e ≥ 1 sont des entiers,
nous noterons Md,e (K) (ou Md,e si aucune confusion n’est à craindre) le K-espace vectoriel
des matrices avec d lignes et e colonnes à coefficients dans K et nous écrivons Md (K) pour
Md,d (K). Nous compterons le nombre d’opérations arithmétiques (additions, multiplications
et inversions) dans K nécessaire pour exécuter l’algorithme. (Rappelons qu’une soustraction est
considérée comme un cas particulier d’une addition.) La complexité de chacune de ces opérations en
terme d’opérations élémentaires variant avec le corps K, il est impossible de décrire la complexité
de l’algorithme de manière indépendante de K.
Le nombre d’opérations nécessaire s’exprime donc en fonction de la taille des matrices concernées. Dans la plupart des cas, nous exprimerons nos conclusions comme une borne de la forme
O(f (d)) pour des matrices ayant au plus d lignes et d colonnes.
A.) Somme de deux matrices. Toute matrice de Md,e possède de coefficients et la somme
de deux matrices se calculent coefficient par coefficient. Le nombre d’opérations arithmétiques
nécessaires est donc de additions dans K.
B.) Produit de deux matrices. Soit M ∈ Md,e et soit N ∈ Me,f . Écrivons M = (mij )
et N = (njk ) où mij (resp. njk ) est le coefficient de M (resp. de N ) situé à l’intersection de la
i-ème ligne et la j-ème colonne de M (resp. à l’intersection de la j-ème ligne et la k-ème colonne
deP
N ). Alors le coefficient à l’intersection de la i-ème ligne et la k-ème colonne de M N est égal
à ej=1 mij njk . Son calcul nécessite e multiplications et e − 1 additions. Enfin, M N contient df
coefficients, et le nombre total d’opérations est d(e − 1)f additions et def multiplications.
De ces remarques on retiendra surtout la conclusion suivante :
Proposition. Le calcul de la somme de deux matrices dont le nombre de lignes et le nombre
de colonnes ne dépassent pas d peut s’effectuer avec O(d2 ) opérations arithmétiques. Le calcul de
leur produit peut s’effectuer avec O(d3 ) opérations arithmétiques.
C.) Opérations sur les lignes et les colonnes. Nous considérons l’échange de deux lignes
ou de deux colonnes comme une opération élémentaire. Soit M ∈ Md,e .
– La multiplication d’une ligne de M par un scalaire (un élément de K) nécessite e multiplications. Par conséquent, l’addition d’un multiple d’une ligne de M à une autre ligne nécessite e
additions et e multiplications.
34
– De même, l’addition d’un multiple d’une colonne de M à une autre colonne nécessite d
additions et d multiplications.
Rappelons que les opérations sur les lignes et les colonnes peuvent être interprétées en termes
de multiplications de matrices. Notons Id ∈ Md la matrice unité et, pour tout couple d’entiers
(d)
(i, j) avec 1 ≤ i, j ≤ d, par Eij la matrice de Md dont le coefficient à l’intersection de la i-ième
ligne et la j-ème colonne vaut 1 et tous les autres coefficients sont nuls. Soit M ∈ Md,e et soit
λ ∈ K.
(L) Ajouter λ fois la i-ème ligne à la j-ème ligne de M équivaut à calculer le produit (Id +
(d)
λEji )M , et
(C) Ajouter λ fois la colonne i-ème colonne à la j-ème colonne de M équivaut à calculer le
(e)
produit M (Ie + λEij ).
(d)
Notons de même Pij désigne la matrice de transposition, définie succinctement par la
(d)
(d)
(d)
formule Pij = Id + Eij + Eji − Eii − Ejj . Notons que Pij = Pji . Alors :
(d)
(PL) Échanger les lignes i et j de M équivaut à calculer le produit Pij M , et
(e)
(PC) Échanger les colonnes i et j de M équivaut à calculer le produit M Pij .
D.) Décomposition LU. Rappelons que son nom est inspiré de l’anglais, L pour lower
(inférieure) et U pour upper (supérieure). Notons Ld la K-algèbre des matrices triangulaires
(1)
infériures dans Md et cLd le sous-ensemble des matrices dont tous les coefficients sur la diagonale principale sont égaux à 1. Notons Ud,e la K-algèbre de matrices triangulaires supérieures
(1)
dans Md,e . L’idée de départ est alors de tenter d’écrire M ∈ comme un produit LU , où L ∈ Ld
et U ∈ Ud,e . Soit donc M ∈ Md,e ; on écrit M = (mij ) comme précédemment.
(a) Supposons d’abord que m11 6= 0. Soit i ∈ {2, . . . , d}. La première étape est créer une
matrice U 0 dont la première colonne est nulle, sauf le coefficient en haut à gauche. Afin d’effectuer
mi1
cette étape, on soustrait, pour tout i ∈ {2, 3, . . . , d}, m
fois la ligne 1 de la ligne i de M . Cela
11
revient calculer le produit de matrices
md1 (d)
md−1,1 (d)
m21 (d)
U 0 = (Id −
Ed1 )(Id −
Ed−1,1 ) · · · (Id −
E )M.
m11
m11
m11 21
(d)
(d)
En remarquant que (Id + λEij )−1 = (Id − λEij ), on constate que M = L0 U 0 , où on a écrit
L0 = (Id +
m21 (d)
m31 (d)
md1 (d)
E21 )(Id +
E31 ) · · · (Id +
E ).
m11
m11
m11 d1
On remarquera que L0 est bien une matrice triangulaire inférieure et que tous ses coefficients sur la
diagonale principale sont égaux à 1. En fait, tous les coefficients non-nuls en dehors de la diagonale
principale se situent dans la première colonne de L0 . Explicitement,




1 0 0 ··· 0
m11 m12 m13 · · · m1e
 m21 1 0 · · · 0
 0 u22 u23 · · · u2e 
m

11


 m31 0 1 · · · 0
0
0
0 u32 u33 · · · u3e  ,
L =  m11
U =
,

 .. .. .. . . .. 
..
..
.. 
..
 ...
 . . .
.
. .
.
.
. 
md1
m11
0 0 ··· 1
0
ud1
ud2 · · ·
ude
mi1
où, pour tout i ∈ {2, 3, . . . , d}, j ∈ {2, 3, . . . , e}, on a écrit uij = mij − m
m1j .
11
(b) Si m11 = 0 il y a deux possibilités.
Ou bien tous les coefficients de la première colonne de M sont nuls. Dans ce cas, on prend
0
L = Id et U 0 = M ; on a alors encore M = L0 U 0 .
35
Ou bien il existe un indice i ∈ {2, 3, . . . , d} tel que mi1 6= 0. On prend alors le plus petit indice
(d)
i avec cette propriété et on échange les lgnes 1 et i de M , ce qui équivaut à remplacer M par Pi1 .
(d)
On peut alors appliquer la procédure du cas (a) pour trouver une décomposition Pi1 M = L0 U 0 .
(d)
En remarquant que Pi1 est égal à son inverse, on a donc
(d)
M = Pi1 L0 U 0 .
(d)
Puisque P1,1 est la matrice unité, cette formule est vraie même dans le cas où m11 6= 0.
En itérant cette procédure, on obtient une décomposition
(d)
(d)
(d)
M = Pi1 ,1 L1 Pi2 ,2 L2 · · · Pir ,r Lr U,
où r = min(d, e) − 1, la matrice U est appartient à Ud,e et, pour tout k ∈ {1, 2, . . . , r}, ik ≥ k.
(1)
Quant aux matrices Lk , elles appartiennent à Ld et, mise à part la diagonale principale, tous les
coefficients non-nuls sont situés dans la k-ième colonne.
(d)
(d)
(d)
Nous noterons L la matrice Pi1 ,1 L1 Pi2 ,2 L2 · · · Pir ,r , malgré le fait qu’elle n’appartient pas à Ld
en général. On a donc M = LU et nous appellerons cette décomposition la décomposition LU
de la matrice M ; elle est uniquement déterminée par la procédure qui vient d’être décrite.
Remarque. Le lecteur prendra garde de ne pas déduire de cette appellation que toute matrice
(1)
M ∈ Md,e s’écrit de façon unique sous la forme LU avec L ∈ Ld et U ∈ Ud,e . Il se peut qu’il n’y
ait aucune décomposition de cette forme, ou s’il y en a, quelle ne soit pas unique.
Éstimons donc le nombre d’opérations arithmétiques nécessaires pour calculer L et U , sans
tenir compte des échanges de lignes. Considérons d’abord le calcul de L0 et de U 0 .
Le calcul de 1/m11 se fait une fois pour toutes. Il s’agit donc d’une inversion.
mi1
Les quotients m
, où 2 ≤ i ≤ d, apparaissent dans la première colonne de L0 et aussi dans le
11
calcul des coefficients uij de U 0 . Leur calcul nécessite d − 1 multiplications.
mi1
Ensuite, pour calculer U , il faut calculer les (d − 1)(e − 1) coefficients uij = mij − m
m1j ,
11
mi1
où 2 ≤ i ≤ d et 2 ≤ j ≤ e. Les d − 1 quotients m11 ayant déjà été calculés, il reste à calculer les
mi1
m1j et enfin le même nombre de soustractions sont nécessaires pour
(d − 1)(e − 1) produits m
11
calculer l’ensemble des uij .
Le nombre total d’opérations nécessaires pour calculer les matices L0 et U 0 est donc :
– une inversion,
– (d − 1) + (d − 1)(e − 1) = d(e − 1) multiplications,
– (d − 1)(e − 1) additions.
Afin de calculer la décomposition LU, cette procédure doit être exécutée r = min (d, e)−1 fois,
successivement sur des matrices de taille (d, e), (d − 1, e − 1), . . .}. Le nombre total d’opérations
arithmétiques est donc
– min
Pr (d, e) − 1 inversions,
– Pk=1 (d + 1 − k)(e − k) multiplications,
– rk=1 (d − k)(e − k) additions.
À nouveau, le point principal à retenir de ces calculs est le suivant.
Théorème. La décomposition LU d’une matrice à au plus d lignes et d colonnes peut être
calculée en utilisant au plus O(d3 ) opérations arithmétiques.
E.) Calcul du déterminant d’une matrice. Notons det M le déterminant de la matrice
M ∈ Md . Rappelons que si M est triangulaire, alors det M est le produit des coefficients sur la
diagonale principale de M . En outre le déterminant de produit de deux matrices est le produit de
36
leurs déterminants. Ces remarques suggèrent l’utilisation de la décomposition LU pour calculer
det M . En effet, si M = LU , alors det M = det L det U = det U et, U étant triangulaire supérieure,
det M est le produit dss coefficients sur la diagonale principale de U . On déduit de la discussion
du calcul de la décomposition LU le résultat suivant.
Théorème. Le déterminant d’une matrice carrée d’ordre d peut être calculé avec un nombre
d’opérations arithmétiques appartenant à O(d3 ).
Remarques. (1) Si det M 6= 0 est inversible, alors tous les coefficients de la diagonale principale
de U sont inversible. Cela implique que, si det M 6= 0, aucune échange de ligne de sera nécessaire.
Par conséquent, la matrice L est triangulaire.
(2) Il existe beaucoup d’autres formules pour le déterminant d’une matrice. Par exemple la
formule
X
det M =
(−1)ε(π) m1,π(1) m2,π(2) · · · md,π(d) ,
π∈Sd
où Sn est le groupe des permutations de {1, 2, . . . , d} et ε(π) est le signe de la permutation π ∈ Sd .
Cette formule est la somme des d! produits de la forme m1,π(1) m2,π(2) · · · md,π(d) , et son exécution
nécessite a priori d!(d − 1) multiplications et d! − 1 additions. Vue la formule de Stirling, il est
clair que, même pour d assez grand, elle est plus complexe que la méthode basée sur le calcul de
la décomposition LU.
Par contre, elle est plus agréable pour les calculs à la main pour les matrices d’ordre deux ou
trois.
F.) Déterminer si oui ou non une famille de vecteurs est libre. Soit M ∈ Md,e . On
constate que les colonnes de M forment une famille libre si et seulement si tous les coefficients sur
la diagonale principale de U sont non-nuls.
En général, si la famille (x1 , x2 , . . . , xe ) d’éléments du K-espace vectoriel V est donnée sous
forme
Pd de combinaisons linéaires des membres d’une base (b1 , b2 , . . . , bd ) de V , par exemple xj =
i=1 λij vi pour tout j ∈ {1, 2, . . . , e}, on forme la matrice associée M = (λij ) et on cherche la
décomposition LU de M .
Vue la discussion précédent, le nombre d’opérations arithmétiques nécessaires appartient à
O(d3 ) dans le cas d’une famille d’au plus d éléments d’un espace vectoriel de dimension au plus
d.
G.) Inversion d’une matrice. Soit M ∈ Md une matrice inversible. À nouveau, l’inverse de
M se calcule facilement à l’aide de la décomposition LU. En effet, si M = LU alors U est inversible
et M −1 = U −1 L1 . Ainsi, on est réduit au calcul de l’inverse d’une matrice triangulaire. Considérons
le calcul de U −1 . Cela revient à résoudre pour V ∈ Md l’équation U V = Id . La matrice V est
alors triangulaire supérieure. Si U = (uij ) avec uij = 0 lorsque i > j , alors V = (vij ) avec vij = 0
lorsque i > j et la diagonale principale de V est déterminée par les équations
u11 v11 = 1,
u22 v22 = 1,
...,
udd vdd = 1,
puis la diagonale vi,i+1 (1 ≤ i ≤ d − 1) par les équations
u11 v12 + u12 v22 = 0,
u22 v23 + u23 v33 = 0,
...,
ud−1,d−1 vd−1,d + ud−1,d vdd = 0,
et ainsi de suite. Un calcul montre que le nombre d’opérations arithmétiques nécessaires pour
calculer U −1 appartient à O(d3 ). Il en est de même pour le nombre d’opérations arithmétiques
nécessaires pour calculer L−1 . Enfin, le calcul du produit U −1 L−1 nécessite encore un nombre
d’opérations appartenant à O(d3 ). Nous avons donc démontré le résultat suivant :
37
Théorème. Le calcul de l’inverse d’une matrice inversible d’ordre d peut s’effectuer avec un
nombre d’opérations arithmétiques appartenant à O(d3 ).
H.) Méthode d’élimination de Gauss. Soit encore M ∈ Md,e . En général, nous savons
que la matrice U = (uij ) de la décomposition LU est une matrice triangulaire supérieure. En
outre, M est de rang maximal min (d, e) si et seulement si tous les coefficients ukk sur la diagonale
principale de U sont non-nuls. Pour des questions plus délicates, comme le calcul du rang ou la
résolution d’un système linéaire, ces informations sont insuffisantes. Par exemple, rien n’empêche
U d’être truffé de zéros comme un morceau de gruyère. Si par exemple


0 u12 u13 u14 0
0 0 u23 u24 0 


,
0
0
u
u
0
U0 = 
33
34


0 0
0
0
0 
0 0
0
0 u55
où seuls les coefficents uij indiqués
peuvent
être non-nuls, alors le rang de U0 dépend entre autre
u23 u24
du rang de la sous-matrice
qui, quant à elle, n’est pas une matrice triangulaire.
u33 u34
Ce problème ne se poserait pas si la matrice U avait la propriété que le premier coefficient non∗
(K) le sous-ensemble
nul se situe strictement à droite de celui de la ligne précédente. Notons Ud,e
de Ud,e (K) formé des matrices avec cette propriété.
La méthode d’élimination de Gauss suit une démarche semblable à celle de la décomposition
LU, mais introduit des échanges supplémentaires de lignes (et éventuellement de colonnes) qui
assurent que la matrice U à la fin possède cette propriété.
Si M = (mij ) ∈ Md,e , on note, pour tout i ∈ {1, 2, . . . , d}, par µM (i) le plus petit indice
j ∈ {1, 2, . . . , e} tel que mij 6= 0. Si la i-ème ligne de M ne contient aucun coefficient non-nul, on
pose µM (i) = e + 1.
(a) Supposons que la première colonne de M contienne au moins un coefficient non-nul. Alors
on échange des lignes de M afin que toutes lignes dont le premier coefficient est non-nul sont situés
au dessus de celles dont le premier coefficient est nul. Si le premier coefficient des k premières lignes
est non-nul, et si k ≥ 2, on soustrait un multiple convenable de la ligne 1 de chacune des lignes
1 à k. Comme dans la déscription de la décomposition LU, cela revient à écrire M sous la forme
(d)
(1)
L0 U 0 , où L est un produit de matrices de la forme Pij et d’une matrice de Ld .
(b) Si la première colonne de M ne contient que des zéros, on échange cette colonne avec la
(e)
dernière colonne non-nulle de M . Cela revient remplacer M par M P1j pour j convenable. On
(e)
peut alors appliquer la méthode de (a) à M P1j . On obtient ainsi une décomposition de la forme
(e)
M = L0 U 0 P1j .
Dans les deux cas, si M 6= 0, le coefficient en haut à gauche de U 0 est non-nul, et tous les
autres coefficients de la première colonne de U 0 sont nulles.
En itérant, on obtient une décomposition de M de la forme
M = LU P,
(e)
∗
où U ∈ Ud,e
et P ∈ Me est un produit de matrices de la forme Pij .
Nous appelerons cette représentation la décomposition gaussienne de M .
Théorème. La décomposition gaussienne d’une matrice ayant au plus d lignes et d colonnes
peut être calculée avec un nombre d’opérations arithmétiques appartenant à O(d3 ).
38
I.) Calcul du rang d’une matrice. Soit M ∈ Md,e et soit M = LU P la décomposition
gaussienne de M . Puisque L et P sont inversibles, le rang de M est égal au rang de U . Mais le
∗
rang d’une matrice appartenant à Ud,e
est égal au nombre de ses lignes qui sont non-nulles.
Théorème. Le rang d’une matrice ayant au plus d lignes et d colonnes peut être calculé avec
un nombre d’opérations arithmétiques appartenant à O(d3 ).
J.) Solution d’un système linéaire d’équations. Le système linéaire de d équations en e
inconnues x1 , x2 , . . ., xe :
a11 x1 + a12 x2 + · · · + a1e xe = b1 ,
a21 x1 + a22 x2 + · · · + a2e xe = b2 ,
..
.
ad1 x1 + ad2 x2 + · · · + ade xe = bd ,
où aij ∈ K et bi ∈ K pour tout i, j, peut être assimilée à l’équation matricielle
Ax = b,
où A = (aij ), x = t (x1 , x2 , . . . , xe ) ∈ Me,1 et b = t (b1 , b2 , . . . , bd ) ∈ Md,1 .
∗
Si la matrice A appartient à Ud,e
, la solution peut s’effectuee par itération, en commençant
avec l’équation correspondant à la dernière ligne non-nulle de A. Si la i-ème ligne est la dernière
ligne non-nulle, l’équation est de la forme
aij xj + ai,j+1 xj+1 + · · · + ai,e xe = bi ,
aij 6= 0,
On considère xj+1 , . . ., xe comme de paramètres et résoudre l’équation permet d’exprimer xj en
fonction de ces paramètres :
xj = − a1ij (bi − ai,j+1 xj+1 − · · · − ai,e xe ).
Cette valeur de xj est ensuite substituée dans l’équation correspondant à la ligne i − 1, et ainsi de
suite.
En général, on décompose le problème en la solution de trois systèmes en utilisant la décomposition gaussienne LU P de A. L’équation matricielle devient alors LU P x = b, qui est équivalente
au système de trois équations Lz = b, U y = z et P x = y.
Comme dans les algorithmes déjà décrits, on constate que le calcul de l’ensemble des solutions
d’un système triangulaire d’au plus d équations avec au plus d inconnus nécessite O(d3 ) opérations
arithmétiques. Puisque la solution d’un système linéare quelconque peut être réduite à la solution
de deux systèmes, le nombre d’opérations arithmétiques nécessaires en général appartient encore
à O(d3 ). En résumé :
Théorème. La solution d’un système linéaire d’au plus d équations en au plus d inconnues
par la méthode d’élimination de Gauss peut s’effectuer avec un nombre d’opérations arithmétiques
appartenant à O(d3 ).
Calcul du déterminant d’une matrice à coefficients entiers
Comme première application de l’utilisation du théorème chinois pour effectuer des calculs
avec les entiers, nous allons étudier le calcul du déterminant d’une matrice à coefficients entiers.
39
Lorsque les coefficients de M sont des entiers, alors le déterminant de M est un entier, mais
en général la méthode décrite basée sur la décomposition LU fera intervenir des dénominateurs
dans les coefficients des matrices intermédiaires.
Une méthode alternative serait de réduire M modulo les nombres premiers successifs p = 2,
3, 5, 7, . . ., calculer son déterminant (mod p) puis retrouver M à l’aide du théorème chinois.
Pour cela, il faut connaı̂tre une borne pour le déterminant d’une matrice en fonction de ces
coefficients.
Une méthode évidente de trouver une telle borne est d’utiliser la formule det M =
P
(π)
m1π(1) m2π(2) · · · mdπ(d) : si b est un majorant des valeurs absolues des coefficients
π∈Sd (−1)
mij on trouve alors que | det M | ≤ d!bd car il y a d! termes dans la somme et chaque produit
m1π(1) m2π(2) · · · mdπ(d) est majoré par bd .
Une meilleure borne est donnée par le résultat suivant :
Théorème (inégalité de Hadamard). Soit M une matrice carrée d’ordre d à coefficients réels.
Alors
| det M | ≤ ||M1 || ||M2 || · · · ||Md || ≤ dd/2 bd ,
où Mk (1 ≤ k ≤ d) est la k-ième ligne de M , ||.|| désigne la norme euclidienne et b est un majorant
des valeurs absolues des coefficients de M .
Bien évidemment, on pourrait utiliser les colonnes de M à la place de ces lignes. On identifie
les lignes de M avec des éléments de Rd .
Quant à la démonstration du théorème, on peut clairement se limiter au cas où les lignes
de M sont linéairement indépendantes, car dans le cas contraire on a det M = 0. On peut alors
faire intervenir la procédé de Gram-Schmidt, qui construit à partir de la base
P (M1 , M2 , . . . , Md )
de Rd une base orthogonale (M1∗ , M2∗ , . . . , Md∗ ) où Mk∗ est de la forme Mk − k−1
j=1 λj Mj pour tout
∗
k ∈ {1, 2, . . . , d}. En replaçant successivement la ligne M1 de M par M1 , la ligne M2 par M2∗ et
ainsi de suite, le déterminant reste inchangé. Par conséquent, si M ∗ désigne la matrice dont les
lignes sont M1∗ , M2∗ , . . ., Md∗ , alors
| det M | = | det M ∗ | = ||M1∗ || ||M2∗ || · · · ||Md∗ ||,
car les lignes de M ∗ forment une base orthogonale de Rd .
En outre, si on désigne par Ek le sous-espace de Rd engendré par (M1 , M2 , . . . , Mk ), alors on
⊥
sait que Mk∗ est la projection orthogonale de Mk sur Ek−1
. Par conséquent, ||Mk∗ || ≤ ||Mk || pour
tout k ∈ {1, 2, . . . , d}. Il s’ensuit que
d
| det M | = ||M1∗ || ||M2∗ || · · · ||Md∗ || ≤ ||M1 || ||M2 || · · · ||Md || ≤ d 2 bd ,
√
où la deuxième inégalité découle des inégalités ||Mk || ≤ db, k ∈ {1, 2, . . . , d}.
Exemples (i ) Si


1 2 3
M = 4 5 6 ,
7 8 9
√
√
√
alors on trouve que | det M | ≤ 12 + 22 + 32 42 + 52 + 62 72 + 82 + 92 ≤ 457, 31. (Si l’on utilise
les colonnes de M , on obtient la borne | det M | ≤ 879, 43.) Par conséquent, det M est déterminé par
sa classe (mod m) si m ≥ d2 × 457, 31e, soit si m ≥ 915. On a 2×3×5×7 < 915 < 2×3×5×7×11.
Afin de déterminer det M , il suffit de le calculer (mod p) pour p ∈ {2, 3, 5, 7, 11}.
(ii ) Si d = 4 et si b = 100, alors on a dd/2 100d = 1, 6 × 109 . Par conséquent, le déterminant
d’une matrice (4, 4) dont tous les coefficients sont inférieurs à 100 en valeur absolue est déterminé
40
par sa classe (mod m) lorsque m ≥ 3, 2 × 109 . Après un calcul, on trouve que ce déterminant est
déterminé par ses classes (mod p) lorsque p parcourt les nombres premiers jusqu’à 29 inclus.
Proposition. La complexité de l’algorithme précédent qui calcule le déterminant d’une matrice
carrée d’ordre d à coefficients entiers et majorés en valeur absolue par b appartient à
O d4 (log d + log b)(log (log d + log b))2 .
Démonstration. Rappelons d’abord que la méthode du pivot de Gauss utilise O(d3 ) opérations
dans le corps K. En outre, si p est un nombre premier, on sait, d’après l’étude des opérations
arithmétiques dans les anneaux Z/mZ, que chacune de ces opérations a un coût appartenant à
O((log p)2 ). Par conséquent, le coût du calcul du déterminant d’une matrice (d, d) à coefficients
dans Z/pZ appartient à O(d3 (log p)2 ).
La complexité du calcul de l’ensemble des déterminants (mod p), p ≤ x appartient donc à
X
(log p)2 ,
O d3
p≤x
Q
D’après ce qui précède, x est à choisir de telle sorte que p≤x p dépasse 2dd/2 bd .
Comme nous avonsQdéjà expliqué, le théorème des nombres premiers (ou l’Exercice 4 de la
1
feuille 6) implique que p≤x p ≥ e 2 x pour tout x assez grand. Il suffit donc de prendre x tel que
1
e 2 x = 2dd/2 bd , soit x = 2 log 2 + d(log d + 2 log b).
Puisqu’il y a au plus x nombres
premiers inférieurs ou égaux à x et puisque la fonction log
P
est croissante, on peut majorer p≤x (log p)2 par x(log x)2 . On en tire que la complexité du calcul
des déterminants (mod p) pour tout p ≤ x appartient à O d4 (log d + log b)(log (log d + log b))2 .
Q
Il reste à estimer la complexité du calcul du déterminant (mod p≤x p), en utilisant le
théorème chinois. D’une part, il y a au plus x nombres premiers inférieurs ou Q
égaux à x. De l’autre
x
part, comme il existe un nombre premier entre x et 2x, on peut majorer p≤x p par 2xe 2 . La
Q
x
complexité du calcul du déterminant (mod p≤x p) appartient donc à O(x(log 2xe 2 )2 ). Puisque
x = 2 log 2+d(log d+2 log b), on voit que cette complexité est négligeable devant celle du calcul du
déterminant pour tout p ≤ x ; elle appartient donc aussi à O d4 (log d + log b)(log (log d + log b))2 .
D’où le résultat.
Cette complexité est meilleure que celle de l’algorithme qui consiste à calculer le déterminant en
réduisant modulo un seul nombre premier p un peu plus grand que 2dd/2 bd . D’après le postulat de
Bertrand, on peut alors choisir le nombre premier p majoré par 4dd/2 bd . Le calcul de det M (mod p)
a alors une complexité appartenant à O(d3 (log p)2 ) ⊆ O(d5 (log d + log b)2 ), où la croissance avec
d est plus rapide par un facteur de d par rapport à l’estimée de la proposition.
Une dernière remarque : nous n’avons pas abordé le problème du calcul des nombres premiers
dont nous avons besoin. En ce qui concerne la méthode appliquant le théorème chinois, ce la ne
pose pas de problème pratique. Il est facile de constituer une liste de tous les nombres premiers
jusqu’à une limite raisonnable. Par exemple, le logiciel pari.gp contient une liste de tous les nombres
premiers jusqu’à environ 500000 (la limite précise dépend de l’installation). D’après le théorème
des nombres premiers
Y
p ≈ e500000
p≤500000
P
et, en fait, un calcul avec pari.gp donne p≤500000 log p ≈ 499318.120. On a donc
Y
p ≈ e499318.120 ≈ 10216851.10 ≈ 2720363.78 .
p≤500000
41
Même si on connaı̂t quelques nombres premiers plus gros que 2720363 , il s’agit surtout de
nombres premiers d’une forme très particulière (par exemple les nombres de Mersenne 2` − 1 avec
` premier). Il est hors de question avec les méthodes et la technologie actuelles de déterminer un
nombre premier dans l’intervalle [2720363 , 2720364 ] dont l’existence est prévue par le postulat de Bertrand. Rappelons que dans les applications cryptographiques, les entiers rencontrés actuellement
dépassent rarement quelques dizaines de milliers de bits.
Multiplication rapide : la méthode de Karatsuba
Nous allons aborder dans les paragraphes qui suivent le sujet de la multiplication rapide.
Notre étude des algorithmes habituels de multiplication dans Z et dans A[x] a montré que le
produit de deux entiers m > 0 et n > 0 peut être calculé en temps O(log m log n) et celui de deux
polynômes f 6= 0 de g 6= 0 degrés respectifs d et e avec O(de) opérations arithmétiques (addition,
soustractions et multiplications) dans l’anneau A. Nous supposerons par la suite que m ' n et
e ' d, de sorte que ces estimations puissent être simplifiées respectivement en O((log n)2 ) et O(d2 ).
La question est de savoir si l’exposant 2 puisse être amélioré : existe-t-il une constante c < 2 et
des algorithmes de multiplication dans Z qui ont un temps de calcul appartenant à O((log n)c ) ?
ou des algorithmes de multiplication dans A[x] dont le nombre d’opérations arithmétiques dans A
appartient à O(dc ) ?
Les premiers algorithmes qui permettait de donner une réponse affirmative à ces questions
étaient proposés par Karatsuba en 1963. L’idée est simple : dans le produit
(pZ + q)(rZ + s) = prZ 2 + (ps + qr)Z + qs,
par la méthode naı̈ve, on calcule les quatre produits apparaissant dans le membre droit pr,
ps, qr et qs, puis on calcule la somme ps + qr. (Dans les applications, Z sera une puissance
d’une indéterminée ou d’un radix et la multiplication par une puissance de Z sera une opération
élémentaire.)
Le point est que la détermination des trois coefficients peut également être effectuée avec
trois multiplications, deux additions et deux soustractions : on calcule pr, qs et (p + q)(r + s), le
coefficient de Z étant alors égal à (p + q)(r + s) − pr − qs.
Considérons donc le cas du produit de deux polynômes f et g ∈ A[x], que l’on suppose de
degré 2d − 1, où d ≥ 1. (Si ce n’est pas le cas, on ajoute des puissances de x dont les coefficients
sont nuls.) On écrit alors
f (x) = p(x)xd + q(x),
g(x) = r(x)xd + s(x),
où p, q, r et s sont des polynômes de degré au plus d − 1. (Par exemple, si f (x) = f0 + f1 x + f2 x2 +
· · · + f2d−1 x2d−1 , alors p(x) = fd + fd+1 x + · · · + f2d−1 x2d−1 et q(x) = f0 + f1 x + · · · + fd−1 xd−1 .)
Le calcul du produit f g des polynômes de degré 2d − 1 est alors réduit au calcul de trois
produits de polynômes de degré au plus d − 1, ainsi que les additions p + q, r + s qui utilisent 2d
opérations dans A, les soustractions (p + q)(r + s) − pq − rs qui utilisent 2(2d) opérations dans A,
et enfin l’addition de ((p + q)(r + s) − pq − rs)xd à p(x)r(x)x2d + q(x)s(x), qui nécessite encore 2d
additions dans A. Si donc T (d) désigne le nombre maximal d’opérations dans A nécessaires pour
calculer le produit de deux polynômes de degré d, on trouve que
T (2d) ≤ 3T (d) + 8d,
42
pour tout d ≥ 1
et donc, en raisonnant par récurrence sur k, que
k
k
T (2 ) ≤ 3 T (1) + 8
k−1
X
3i · 2k−1−i = 3k T (1) + 8(3k − 2k )
i=0
pour tout k ≥ 0. Puisque T (1) = 1, on en tire le résultat suivant.
Théorème. Soit k ≥ 0 un entier et soit A un anneau. Alors le produit de deux polynômes à
coefficients dans A[x] de degré au plus 2k − 1 peut être calculé en effectuant au plus 9 · 3k − 2k+3
opérations arithmétiques dans A.
Lorsque d n’est pas forcément une puissance de 2, on tire le corollaire suivant en prenant pour
k l’entier vérifiant 2k−1 < d ≤ 2k :
Corollaire La multiplication de deux polynômes de degré d − 1 à coefficients dans l’anneau A
peut s’effectuer en utilisant O(dlog2 3 ) opérations arithmétiques dans A.
Puisque log2 3 ' 1, 585, on a une amélioration très nette par rapport à la multiplication naı̈ve
dans A[x].
Un algorithme semblable existe pour la multiplication de deux entiers écrits en base b. Si
m > 0 et n > 0 ont pour chiffre dominant celui de b2d−1 , on écrit
m = pbd + q,
n = rbd + s,
0 ≤ p, q, r, s ≤ bd − 1.
(Si m et n sont écrits en base b, les calculs de p, q, r et s sont des opérations élémentaires.) À
nouveau, on écrit
mn = pqb2d + ((p + q)(r + s) − pq − rs)bd + rs.
Si T (d) désigne le temps de calcul en base b du produit de deux entiers inférieurs à bd , alors on a
encore une inégalité de la forme
T (2d) ≤ 3T (d) + Cd,
aves unc constante C > 0, car si on connaı̂t pq, rs et (p + q)(r + s) en base b, le reste du calcul
consiste en des additions et les soustractions dont la complexité appartient à O(d) = O(log n)).
On trouve alors par récurrence sur k que
k
k
T (2 ) ≤ 3 T (1) + C
k−1
X
3i 2k−1−i = 3k T (1) + C(3k − 2k ),
i=0
ce qui implique encore un temps de calcul appartenant à O(dlog2 3 ) = O((log n)log2 3 ).
Théorème. Le produit de deux entiers inférieurs ou égaux à n peut être calculé en temps
O((log n)log2 3 ).
Remarque. Soit r ≥ 2 un entier. En découpant les polynômes de degré rd − 1 en r blocs de
d termes, on obtient un algorithme du calcul du produit de deux polynômes de degré au plus d
dont la complexité appartient à O(log d)logr (2r−1) . Puisque logr (2r − 1) → 1 lorsque r → +∞, on
peut, en fait, réaliser un temps de calcul appartenant à O(d(1+) ) quelque soit le réel > 0. Mais
la constante C telle que T (d) ≤ Cd(1+) pour tout d assez grand, ainsi que la valeur minimale de d
sous-entendue par le assez grand , tendent vers +∞ lorsque → 0+ , et l’algorithme n’est guère
utilisé lorsque r ≥ 3. Il y a des algorithmes semblables pour la multiplication de deux entiers.
La transformée de Fourier rapide, que nous allons bientôt expliquer, permet d’obtenir des algorithmes plus pratiques et d’une meilleure complexité, au moins dans le cas d’anneaux particuliers.
43
Calcul rapide du produit de deux matrices
Soit donc encore A un anneau ; on note Md,e (A) le A-module de matrices à d lignes et e
colonnes à coefficients dans A. Nous allons mentionner brièvement le calcul rapide du produit de
deux matrices par un algorithme semblable à celui de Karatsuba.
Pe Si M = (Mij ) ∈ Md,e (A) et si N = (Nij ) ∈ Me,f (A), la matrice produit M N a mp coefficients
k=1 Mik Nkj , (1 ≤ i ≤ d, 1 ≤ j ≤ f ). Chaque somme fait intervenir e multiplications et e − 1
additions dans A. La méthode naı̈ve de calcul de M N fait donc intervenir def multiplications et
d(e − 1)f additions. En particulier, si d = e = f , on voit que le calcul du produit M N nécessite
n3 multiplications et d2 (d − 1) additions, et la complexité appartient donc à O(d3 ).
En s’inspirant de l’algorithme de Karatsuba, on peut diminuer l’exposant 3. À nouveau, l’idée
est de réduire la multiplication de deux matrices de taille 2d à la multiplication de matrices de
taille d, et de procéder récursivement. (Si la matrice est d’ordre impair, on peut l’agrandir en une
matrice d’ordre pair en ajoutant une ligne et une colonne de zéros ; on peut donc supposer sans
perte de généralité que d est pair.) On écrit alors les matrices M et N de taille 2d en blocs :
M1 M2
N1 N2
M=
,
N=
,
M3 M4
N3 N4
où Mi et Ni (1 ≤ i ≤ 4) sont des matrices carrées de taille d. Alors le produit matriciel
M1 N1 + M2 N3 M1 N2 + M2 N4
MN =
M3 N1 + M4 N3 M3 N2 + M4 N4
fait intervenir 8 produits et 4 additions de matrices d’ordre d.
Le point est que les 4 matrices d’ordre d peuvent être écrits comme combinaisons linéaires de
seulement sept produits. En effet, si l’on pose
P1 = M1 N1 ,
P2 = M2 N3 ,
P4 = M4 (N1 − N2 − N3 + N4 ),
P6 = (−M1 + M3 + M4 )(N1 − N2 + N4 ),
P3 = (M1 + M2 − M3 − M4 )N4 ,
P5 = (M3 + M4 )(−N1 + N2 )
P7 = (M1 − M3 )(−N2 + N4 ),
alors on constate que
MN =
P1 + P2
P1 + P3 + P5 + P6
P1 − P 4 + P6 + P 7 P1 + P5 + P6 + P7
En prenant soin à la programmation des additions, on en tire que si T (d) désigne le temps de
calcul du produit de deux matrices carrées d’ordre d, alors
T (2d) ≤ 7T (d) + 15d2
pour tout d ≥ 1. En raisonnant par récurrence sur k et en remarquant que T (1) = 1, on trouve
que
T (2k ) ≤ 6 · 7k
quelque soit k ≥ 0 et donc T (d) ∈ O(dlog2 7 ) au moins lorsque d parcourt les puissances de 2. En
bordant une matrice de taille quelconque de zéros, on trouve le résultat suivant.
Théorème. Soit A un anneau. Le produit de deux matrices carrées d’ordre d à coefficients
dans A peut être calculé en utilisant O(dlog2 7 ) opérations arithmétiques dans A.
44
Puisque log2 7 ' 2, 807, cela améliore l’exposant 3 de l’algorithme naı̈f.
L’algorithme qui vient d’être décrit est une variante d’un algorithme proposé par Strassen en
1969.
La transformée de Fourier rapide
La transformée de Fourier rapide (FFT pour Fast Fourier Transform en anglais) est une
méthode de multiplication rapide basée sur la transformée de Fourier finie. Dans sa forme de base,
elle nécessite la présence, dans l’anneau A de racines de l’unités appropriées. Elle ne peut donc
pas s’appliquer directement à l’arithmétique des entiers ou dans A[x] lorsque A est arbitraire ; une
solution serait de l’appliquer dans certains anneaux quotients (corps finis, anneaux de la forme
A[x]/(xd − 1), . . .,) puis utiliser le théorème chinois pour déduire le résultat cherché.
Soit d ≥ 1 un entier et soit f ∈ A[x] un polynôme de degré au plus d − 1. Si A est un corps,
on peut récupérer f à partir de ses valeurs en d points deux-à-deux distincts a1 , a2 , . . ., ad ∈ A
en utilisant la formule d’interpolation de Lagrange
f (x) =
d
X
f (ar )Pr (x),
où
r=1
Q
s6=r (x − as )
Pr (x) = Q
.
s6=r (ar − as )
Remarquons que les polynômes Pr apparaissant dans la formule de Langrange ne dépendent
que des éléments ar (1 ≤ r ≤ d). Ainsi, une fois les Pr calculés, chaque coefficient du polynôme f
peut être calculé avec d multiplications et d − 1 additions. Puisque f est de degré au plus d − 1,
son, calcul à partir des Pr nécessite d(d + 1) multuplications et d(d − 1) additions.
Si g ∈ A[x] est un second polynôme de degré au plus d − 1, alors f g est déterminé par 2d − 1
produits f (ar )g(ar ), où {ar }1≤r≤2d−1 sont des éléments deux-à-deux distincts de A. Cela suggère
une procédure de calcul de f g : on calcule les 2(2d − 1) éléments f (ar ) et g(ar ), 1 ≤ r ≤ 2d − 1,
puis les 2d − 1 produits f (ar )g(ar ) puis de récupére f g à l’aide de la formule de Lagrange. Si
l’on avait une méthode rapide de calcul les f (ar ) et les g(ar ), puis de reconstruire f g à partir
des produits f (ar )g(ar ), on aurait réduit le calcul de f g au calcul des 2d − 1 produits f (ar )g(ar ),
(1 ≤ r ≤ 2d − 1). On pourrait ainsi espérer obtenir un algorithme plus rapide du calcul de f g.
En rappelant notre discussion de l’évalution d’un polynôme et le schéma de Horner, on voit que
le calcul de l’une des valeurs f (ar ) et g(ar ) nécessite 2(d − 1) opérations dans A. Par conséquent,
le calcul de l’ensemble de ces 2(2d − 1) valeurs lorsque r parcourt {1, 2, . . . , 2d − 1} nécessite
4(d − 1)(2d − 1) ∈ Θ(d2 ) opérations dans A, et cette partie du calcul aura encore une complexité
dans Θ(d2 ).
Afin d’obtenir un algorithme plus efficace, on fait un choix particulier des ar . Et c’est là où
intervient des racines de l’unité.
Enfin, afin de simplifier la notation, nous noterons d − 1 une majoration des degrés de f , de g
et de f g : si deg f g ≥ d, nous algorithmes le reste de la division euclidienne de f (x)g(x) par xd .
Soit donc R 6= {0} un anneau (commutatif et unitaire, comme toujours), soit d ∈ N, d ≥ 1 et
soit ζ ∈ R. On dit que ζ est une racine d-ième de l’unité si ζ d = 1. On dit que ζ est une racine
primitive d-ième de l’unité s’il s’agit d’une racine d-ième de l’unité et, pour tout entier t vérifiant
1 ≤ t < d, ζ t − 1 n’est pas un diviseur de 0 dans R (dans ce cours, 0 est compté comme un diviseur
de zéro).
45
Ces définitions sont bien connues lorsque R est un corps ou un anneau intègre. Dans ce cas,
la condition que ζ t − 1 ne soit pas un diviseur de zéro équivaut à la condition habituelle ζ t 6= 1.
Par contre, en algorithmique, il est fort utile d’utiliser des anneaux qui ne sont pas nécessairement
intègres, même si le résultat final concerne un anneau intègre.
Les racines d-ièmes de l’unité appartenant à R forme un sous-groupe du groupe des éléments
inversibles de R, qui nous noterons µd (R). (Cette notation s’inspire de celle utilisée en géométrie
algébrique ; je ne connais pas d’autre notation dont l’usage est répandu.) En particulier, si r ∈ Z
et si ζ ∈ µd (R), alors ζ r ne dépend que du résidu de r (mod d). On note µ∗d (R) l’ensemble des
racines primitives d-ièmes de l’unité appartenant à R.
2
Exemple. Si R = Z/8Z, alors 3 = 1, 3 6= 1 mais 3 n’appartient pas à µ∗2 (R), car 3 − 1 est un
diviseur de zéro.
Lemme 1. Soit ζ ∈ µ∗d (R) et soit ` un entier, 0 ≤ ` < d. Alors
(
d−1
X
d,
si ` = 0,
ζ k` =
0,
sinon.
k=0
Démonstration. Il est clair que
d−1
X
k=0
ζ
k`
=1+
Pd−1
d−1
X
k=0
ζ
k=1
k`
ζ k` = 1 lorsque ` = 0. Si ` 6= 0, alors
d`
=ζ +
d−1
X
ζ
k`
=
k=1
d
X
k=1
ζ
k`
=ζ
`
d−1
X
ζ k`
k=0
P
d−1 k`
= 0. On conclut grâce à l’hypothèse que 1 − ζ ` n’est pas un diviseur
ζ
et donc (1 − ζ ` )
k=0
de zéro.
Supposons donc que R contienne une racine primitive d-ième de l’unité ζ. Soit donc f ∈ R[x]
de degré au plus d−1. On identifie f (x) = f0 +f1 x+· · ·+fd−1 xd−1 avec l’élément (f0 , f1 , . . . , fd−1 )
de Rd et on considère la transformée de Fourier discrète (DFT pour discrete Fourier transform
en anglais), qui est l’endomorphisme Tζ du R-module Rd défini par
Tζ (f0 , f1 , . . . , fd−1 ) = f (1), f (ζ), f (ζ 2 ), . . . , f (ζ d−1 )
Alors la matrice de Tζ dans la base standard de Rd est la

1 1
1
···
2
1 ζ
ζ
···

4
1 ζ 2
ζ
···
Vζ = 
 ..
..
..
...
.
.
.
1 ζ d−1 ζ 2(d−1) · · ·
matrice de Vandermonde

1
ζ d−1 

ζ 2(d−1) 
,
.. 
. 
(d−1)2
ζ
dont le terme à l’intersection de la i-ième ligne et la j-ième colonne est ζ (i−1)(j−1) .
Lemme 2. Soit ζ ∈ µ∗d (R). Alors
Vζ Vζ −1 = dId ,
Id étant la matrice identité d’ordre d.
Ce Lemme découle immédiatement du Lemme 1. On tire de la discussion qui précède le résultat
suivant :
46
Proposition 1. Soit R un anneau, soit d ≥ 1 un entier et soit ζ ∈ µ∗d (R). On suppose en
plus que d soit un élément inversible de R. Alors la transformée de Fourier discrète Tζ est un
automorphisme de Rd , et l’homomorphisme inverse Tζ−1 est égal à d−1 Tζ −1 .
Si f et g ∈ R[x] sont de degré au plus d − 1, alors leur convolée d’ordre d est, par définition,
le polynôme f (x)g(x) (mod xd − 1) (c’est-à-dire le reste de la division euclidienne de f (x)g(x) par
xd − 1). On la note f ∗d g. On remarque que, lorsque deg f g < d, alors f ∗d g = f g.
Proposition 2. On reprend les hypothèses de la Proposition 1. Pour tout f , g ∈ R[x] de degré
au plus d − 1, on a Tζ (f ∗d g) = Tζ (f )Tζ (g).
Ici, Tζ (f )Tζ (g) désigne le produit composante par composante des éléments Tζ (f ) et Tζ (g) de
Rd . Grâce à la linéarité de Tζ et du reste de la division euclidienne par un polynôme fixé, il suffit
de vérifier la formule lorsque f (x) = xa et g(x) = xb sont des monômes, 0 ≤ a < d et 0 ≤ b < d.
On a
Tζ (xa ) = (1, ζ a , ζ 2a , . . . , ζ (d−1)a ),
Tζ (xb ) = (1, ζ b , ζ 2b , . . . , ζ (d−1)b ),
d’où Tζ (xa )Tζ (xb ) = (1, ζ a+b , ζ 2(a+b) , . . . , ζ (d−1)(a+b) ).
Si a + b < d, alors (1, ζ a+b , ζ 2(a+b) , . . . , ζ (d−1)(a+b) ) = Tζ (xa+b ) et si a + b ≥ d, alors
(1, ζ a+b , ζ 2(a+b) , . . . , ζ (d−1)(a+b) ) = (1, ζ a+b−d , ζ 2(a+b−d) , . . . , ζ (d−1)(a+b−d) ) = Tζ (xa+b−d ).
Pour conclure, il suffit de remarquer que le reste de la division euclidienne de xa+b par xd est égal
à xa+b lorsque a + b < d et à xa+b−d lorsque a + b ≥ d.
Tout cela est de la belle théorie mais, afin d’obtenir un algorithme rapide, il faut encore
savoir comment calculer rapidement Tζ (f ) = (f (1), f (ζ), . . . , f (ζ d−1 )). L’idée est, comme chez
l’algorithme de Karatsuba, de procéder de façon récursive. L’algorithme présenté dans les lignes
qui suivent et l’une des variantes de la transformée de Fourier rapide.
Supposons que d soit pair. Alors xd − 1 = (xd/2 − 1)(xd/2 + 1) et on note respectivement
f (x) = q1 (x)(xd/2 − 1) + r1 (x),
f (x) = q2 (x)(xd/2 + 1) + r2 (x)
les divisions euclidiennes avec reste de f (x) par xd/2 −1 et par xd/2 −1, de sorte que deg r1 , deg r2 <
d
− 1. Vue la forme très particulière des polynômes xd/2 ± 1, le calcul de r1 et de r2 est aisé : si l’on
2
écrit f (x) = f1 (x)xd/2 +f2 (x) avec deg f1 , deg f2 < d2 −1, on a f (x) = f1 (x)(xd/2 ±1)∓f1 (x)+f2 (x),
d’où r1 (x) = f1 (x) + f2 (x) et r2 (x) = −f1 (x) + f2 (x). Ainsi, le calcul de r1 et de r2 nécessite au
plus d additions dans R.
Soit a ∈ N. Si a est pair, a = 2`, alors (ζ a )d/2 = ζ `d = 1 et donc
f (ζ a ) = q1 (ζ a )((ζ a )d/2 − 1) + r1 (ζ a ) = r1 (ζ a ).
Si a est impair, a = 2` + 1, alors (ζ a )d/2 = ζ `d ζ d/2 = ζ d/2 . En outre, (ζ d/2 − 1)(ζ d/2 + 1) =
ζ − 1 = 0. Puisque ζ est une racine primitive d-ième de l’unité, ζ d/2 − 1 n’est pas un diviseur de
zéro. Par conséquent, ζ d/2 + 1 = 0 et donc ζ d/2 = −1. Il s’ensuit que
d
f (ζ a ) = q2 (ζ a )((ζ a )d/2 + 1) + r2 (ζ a ) = q2 (ζ a )(ζ d/2 + 1) + r2 (ζ a ) = r2 (ζ a ).
Si l’on pose ω = ζ 2 , alors ω ∈ µ∗d/2 (R) et l’on a
f (ζ a ) = r1 (ω a/2 ) (a pair),
f (ζ a ) = r2∗ (ω (a−1)/2 ) (a impair),
47
où r2∗ (x) = r2 (ζx). Le calcul de r2∗ (x) se fait à partir de r2 (x) en multipliant les coefficients de r2
par des puissances de ζ ; puisque deg r2 < d2 − 1, il y a d2 multiplications par des puissances de ζ
à effectuer.
En faisant varier a de 0 à d − 1, on trouve que
d
d
f (1), f (ζ), f (ζ 2 ), f (ζ 3 ) . . . , f (ζ d−2 ), f (ζ d−1 ) = r1 (1), r2∗ (1), r1 (ω), r2∗ (ω), . . . , r1 (ω 2 −1 ), r2∗ (ω 2 −1 ) .
Quitte à permuter les termes, le calcul du d-tuple f (1), f (ζ), f (ζ 2 ), f (ζ 3 ) . . . , f (ζ d−2 ), f (ζ d−1 )
d
est alors réduit au calcul des deux d2 -tuples de la même forme r1 (1), r1 (ω), . . . , r1 (ω 2 −1 ) et
d
r2∗ (1), r2∗ (ω), . . . , r2∗ (ω 2 −1 ) . Le coût de ce calcul est le coût du calcul de r1 et de r2∗ , soit d
additions et d/2 multiplications par des puissances de ζ.
Supposons donc que d soit une puissance de 2, d = 2k . On peut alors appliquer récursivement
la procédure qui vient d’être décrite. À partir de f de degré (au plus) 2k −1, on obtient 2 polynômes
de degré au plus 2k−1 − 1, puis 4 polynômes de degré au plus 2k−2 − 1, et ainsi de suite. Après
k étapes, on trouve 2k polynômes constants dont les valeurs sont f (ζ a ) avec 0 ≤ a ≤ 2k − 1. Le
coût de chacune des étapes est encore 2k additions et 2k−1 multiplications, et on en déduit donc
le résultat suivant.
Théorème. Soit R un anneau, soit k ≥ 1 un entier. On suppose que µ∗2k (R) 6= ∅. Alors la
transformée de Fourier discrète d’un polynôme f ∈ R[x] de degré au plus 2k − 1 peut être calculée
à l’aide de k2k additions et k2k−1 multiplications dans R.
Corollaire 1. On reprend les hypothèses du Théorème et on suppose en plus que 2 est inversible
dans R. Si f , g ∈ R[x] sont de degré au plus 2k − 1, alors la convolée f ∗2k g peut être calculée à
l’aide de 3k2k additions et 3k2k−1 + 2k multiplications dans R.
Démonstration du Corollaire. Soit ζ ∈ µ∗2k (R). En utilisant la Proposition 2, on voit que
1
f ∗2k g = k Tζ −1 Tζ (f )Tζ (g) .
2
D’après le Théorème, le calcul de Tζ (f ) nécessite k2k additions et k2k−1 multiplications. De même
pour Tζ (g). Le produit Tζ (f )Tζ (g) se calcule alors avec 2k multiplicatione et, enfin, le calcul de
Tζ −1 (Tζ (f )Tζ (g)) nécessite encore k2k additions et k2k−1 multiplications.
Corollaire 2. La multplication de deux polynômes de degré au plus d − 1 et à coefficients dans
un anneau R où 2 est inversible et contenant une racine primitive 2n -ième de l’unité avec 2n ≥ 2d
peut être effectuée à l’aide d’au plus O(d log d) opérations dans l’anneau R.
n/`
C’est une conséquence de ce qui précède, en notant que si ζ ∈ µ∗2n (R), alors ζ 2 ∈ µ∗2` (R)
lorsque 0 ≤ ` ≤ n. On prend pour ` le plus petit entier tel que 2` ≥ 2d. Si f et g ∈ R[x] sont de
degré au plus d, alors f g = f ∗2` g.
Quelques applications de la transformée de Fourier rapide
Dans le ce paragraphe, nous indiquons la FFT puissent être appliquée aux calculs dans des
anneaux ne contenant pas les racines de l’unité requises.
2πi
Tout d’abord le cas K = C. Alors on prend traditionnellement ζd = e− d . Ainsi dans les cours
de théorie du signal, par exemple, la transformée de Fourier discrète est le plus souvent définie
par la formule
d−1
X
2πikt
ˆ
f (t) =
fk e − d ,
k=0
48
où (f0 , f1 , . . . , fd−1 ) ∈ Cd est souvent vu comme une sous-famille extraite d’une suite (fk ) indexée
par k ∈ N ou par k ∈ Z. Si a est un entier, on a alors fˆ(a) = Tζd (a). La formule Tζ−1
= d1 Tζ −1 est
d
d
équivalente à la formule d’inversion :
d−1
2πika
1X ˆ
f (k)e d ,
fa =
d k=0
(0 ≤ a ≤ d − 1).
Parmi des exemples d’anneaux les plus utiles en algorithmique qui contiennent des racines de
l’unité on trouve les corps finis, et certains anneaux de la forme A[x]/(xd − 1), ou A[x]/P (x), où
P est le polynôme minimal d’une racine de l’unité.
Considérons d’abord le cas d’un corps fini. Notons Fq un corps fini à q éléments.
Lemme 1. Soit d ≥ 1 un entier. Le corps Fq contient une racine primitive d-ième de l’unité
si et seulement si d divise q − 1.
Démonstration. En effet, le groupe multiplicatif F×
q des éléments non nuls de Fq est alors
cyclique d’ordre q − 1. Il suffit alors de rappler le résultat général suivant concernant les groupes
cycliques.
Lemme 2. Soit n ≥ 1 un entier et soit G un groupe d’ordre n. Alors l’ordre d’un élément
de G divise n. Si de plus G est cyclique et si d ≥ 1 est un diviseur de n, alors G contient φ(d)
éléments d’ordre d.
Ici, comme auparavant, φ désigne la fonction indicatrice d’Euler, c’est-à-dire le nombre d’entiers a ∈ {1, 2, . . . n} premiers à n, ou encore le cardinal du groupe des éléments inversible (Z/nZ)×
de l’anneau Z/nZ.
On trouvera la démonstration du Lemme 2 dans n’importe quel cours d’algèbre niveau L3 ou
M1.
Il résulte du Lemme 1 que les nombres premiers p de la forme 2k t + 1 avec t petit ont un
intérêt particulier, car le corps Fp contient alors une racine primitive 2k -ième de l’unité et on peut
appliquer FFT pour calculer le produit de deux polynômes de Fp [x] de degré au plus 2k−1 − 1. (Je
ne donnerai pas de sens précis à l’expression t petit , mais il faut rappeler que la complexité
des calculs dans Fp augmentent avec p ; il y a donc souvent intérêt à supposer (p − 1)/2k aussi
petit que possible.)
Supposons maintenant qu’on veut multiplier deux polynômes f , g ∈ Z[x] de degré au plus
2 −1 et dont les coefficients sont bornés en valeur absolue par un nombre B > 0. Les coefficients
de f g sont alors bornés par 2k−1 B 2 . Si donc on choisit un nombre premier p ≡ 1 (mod 2t ) et
vérifiant p ≥ 2k−2 B 2 , on peut calculer le produit f g (mod p) avec FFT puis remonter et trouver
ainsi f g. Puisque tous les coefficients concernés sont inférieurs à p, le coût de la redaction (mod
p) et du remontage appartiennent à O(2k ), et on a un algorithme qui, en principe, calcule f g avec
O(k2k ) opérations arithmétiques dans Fp .
Cette analyse est correcte en principe, mais cache un certain nombre de difficultés. Le premier
problème est, étant donnés k et B, de trouver un nombre premier p avec les propriétés requises.
Or, on a le résultat suivant.
k−1
Théorème (Dirichlet). Soit n ≥ 1 un entier et soit a ∈ Z premier à n. Alors il existe une
infinité de nombres premiers p vérifiant p ≡ a (mod n). Plus précisément, si π(x) désigne le
nombre de nombres premiers inférieurs ou égaux à x et si π(x; n, a) désigne le nombre de nombres
premiers p ≤ x tels que p ≡ a (mod n), alors
π(x; n, a)
1
=
.
x→+∞
π(x)
φ(n)
lim
49
Ce résultat dit que les nombres premiers sont équidistribués entre les φ(n) classes d’entiers
(mod n) qui sont premiers à n. (On remarquera que si a n’est pas premier à n, il n’y a qu’un
nombre fini de nombres premiers p tels que p ≡ a (mod n).) On trouvera la démonstration du
théorème de Dirichlet dans de nombreux cours de théorie analytique des nombres. Voir par exemple
le chapitre II.8 du livre de G. Tenenbaum déjà cité. Elle est tout à fait accessible à des étudiants
de niveau M1-M2, mais la détailler en cours prendra trop de temps.
On tire du théorème de Dirichlet l’existence d’un nombre premier p satisfaisant aux deux
conditions p ≡ 1 (mod 2k ) et p ≥ 2k−2 B 2 . Mais, malheureusement, nous ne disposons pas, lorsque
k ≥ 2, d’une majoration du plus petit nombre premier p répondant à ces conditions aussi explicite
et simple que celle fournit par le postulat de Bertrand lorsque k = 1.
Quelques algorithmes heuristiques et probabilistes
À la fin de la dernière section, nous avons remarqué que nous ne disposons pas d’estimée aussi
précise que le postulat de Bertrand pour le plus petit nombre premier p ≡ 1 (mod 2k ) supérieur à
une borne donnée. (On pourra consulter la page consacrée au Théorème de Linnik dans Wikipédia
pour des informations succinctes sur ce problème.)
Par ailleurs, le postulat de Bertrand montre que si n ≥ 1, il existe un nombre premier dans
l’intervalle ]n, 2n]. Dans les applications en vue, nous avons besoin d’un seul nombre premier plus
grand que n, et dane le pire des cas, ce nombre premier pourrait a priori être proche de 2n. Or,
tester tous les n entiers entre n + 1 et 2n nécessite n tests de primalité, alors que nous sommes
habitués à des algorithmes de complexité appartenant à O(log n) ou à O((log n)2 ). Et nous n’avons
pas (encore) discuté des tests de primalité et leur complexité. . .. (Bien entendu, on pourrait enlever
tous les entiers divisibles par des petits nombres premiers, mais il en restera toutefois un nombre
proportionnel à n à tester.)
Toutefois, le théorème des nombres premiers suggèrent que les nombres premiers sont beaucoup
plus fréquents. En effet, il suggère que, si h ≥ 0, le nombre de nombres premiers contenu dans
l’intervalle ]n, n/h] devrait être à peu près égal à
n+h
n
−
.
log(n + h) log n
Si h est petit par rapport à n, cette quantité est à peu près égale à logh n ; autrement dit, dans un
intervalle de longueur h commençant avec n + 1, le nombre de nombres premiers devrait êtrev égal
à environ logh n . En moyenne donc, on s’attend à ce qu’il fait essayer environ log n entiers n + 1,
n + 2, . . ., avant de tomber sur un nombre premier. On pourrait également dire que la probabilité
que l’entier n soit un nombre premier est log1 n .
Les deux points importants à retenir sont : (a) d’une part, on ne sait absolument pas rendre
rigoureux cet argument avec nos connaissances mathématiques actuelles et : (b) en pratique, ça
marche, c’est-à-dire, si on se donne un entier naturel n et si on teste pour primalité successivement
les entiers n + 1, n + 2, . . ., on rencontre en moyenne un nombre premier après au plus environ
log n essais, et il est rare qu’on soit obligé d’aller bien au-delà. Ainsi, l’algorithme qui consiste à
tester successivement n + 1, n + 2, . . ., jusqu’à ce qu’on trouve un nombre premier et très souvent
utilisé lorsqu’on cherche un nombre premier un peu plus grand que n. En pratique, le nombre de
tests de primalité dont on a besoin appartient à O(log n), alors que le postulat de Bertrand affirme
qu’en principe on a besoin d’un nombre de tests appartenant à O(n).
50
Cette question est manifestement liée au problème de la différence entre deux nombres premiers
successifs. Pour une résumé de nos connaissances actuelles sur cette question on pourrait à nouveau
consulter Wikipédia.
La détermination du plus petit nombre premier est donc un exemple d’un problème algorithmique dont la complexité en pratique est beaucoup meilleure que celle qui peut être
démontrée avec les techniques mathématiques d’aujourd’hui. Il en est de même pour le calcul
du plus petit nombre premier plus grand que n et appartenant à une suite arithmétique vérifiant
les hypothèses du théorème de Dirichlet. Si n0 est le plus petit membre de la progression plus
grand que n, on constate qu’il suffit, en moyenne de tester log n éléments de la progression en
commençant par n0 , au moins si n est grand par rapport au rapport de la progression.
Ce genre d’algorithme est souvent dénommé un algorithme heuristique et on parle de
sa complexité heuristique. La notion d’algorithme heuristique est à distinguer de celle d’algorithme probabiliste, qui est généralement réservée aux algorithmes qui font appel à des données
tirées au hasard. Des algorithmes probabilistes sont souvent utilsés en cryptographie et, sans entrer
dans les détails de ces applications, nous allons décrire quelques exemples de base.
Voici donc un exemple simple d’un algorithme probabiliste, qui est utilisé dans la pratique.
Soit p un nombre premier impair. Comment trouver un entier a premier à p qui n’est pas un carré
(mod p) ? Si p ≡ 1 (mod 4) il suffit de prendre a = −1 (voir l’Exercice 3 de la feuille 8), mais si
p ≡ 3 (mod 4), il n’y a pas de formule aussi simple fournissant un entier a qui est un non carré
(mod p).
Il s’avère alors que la méthode la plus simple de construire a est de le choisir au hasard. Il y
(p − 1)/2 carrés non nuls et (p − 1)/2 non-carrés (mod p). La probabilité que a soit un non carré
est donc 1/2. La probabilité donc qu’au bout de k essais on n’a toujours pas trouvé un non-carré
est donc 1/2k , ce qui est déjà inférieure à une millième lorsque k = 10.
Rappelons comment tester si a est un carré (mod p) ou non :
Proposition. Soit p un nombre premier impair. On note Fp le corps Z/pZ et F×
p son groupe
multiplicatif.
p−1
p−1
(i) F×
p contient 2 carrés et 2 non carrés.
Soit α ∈ F×
p.
p−1
p−1
(ii ) On a soit α 2 = 1 soit α 2 = −1.
p−1
2
(iii ) Pour que α soit un carré de F×
= 1.
p , il faut et il suffit que α
Démonstration. (i ) Considérons le morphisme de groupe
×
ψ : F×
p → Fp ,
ψ(α) = α2 .
Alors le noyau ker ψ de ψ est formé des éléments α tels que α2 = 1, c’est-à-dire ker ψ est l’ensemble
des racines du polynôme x2 − 1. Ce polynôme étant de degré deux, il possède au plus deux racines
dans le corps Fp . Mais 1 et −1 sont manifestement des racines, qui sont distinctes, car p est
impair. Par conséquent, ker ψ est composé des deux éléments 1 et −1 ; il est donc d’ordre deux.
p−1
Par conséquent, l’image de ψ est un groupe d’ordre p−1
, ce qui signifie que F×
p contient 2 carrés.
2
p−1
p−1
Puisque F×
p est d’ordre p − 1, il contient (p − 1) − 2 = 2 non carrés.
p−1
p−1
(ii ) Puisque F×
= 1. Par conséquent, (α 2 )2 = 1 et
p est un groupe d’ordre p − 1, on a α
p−1
(α 2 )2 est une racine du polynôme x2 − 1, donc égal à 1 ou à −1.
p−1
2
2
(iii ) Si α est un carré de F×
= β p−1 = 1. Afin de démontrer la réciproque,
p , α = β , alors α
p−1
p−1
2
on interprète les éléments α de F×
= 1 comme des racines de x 2 − 1. D’après
p qui vérifient α
p−1
p−1
2
le (i ), F×
− 1. Les carrés
p contient 2 carrés, que nous venons de voir sont des racines de x
51
p−1
fournissent donc p−1
racines du polynôme x 2 − 1. Ce polynôme étant de degré
2
p−1
pas d’autres racines. On conclut que si α n’est pas un carré, alors α 2 6= 1.
p−1
,
2
il ne possède
Le crible d’Ératosthène
Soit n ≥ 1 un entier. Comment tester n pour savoir si n est un nombre premier ou non ?
Comment factoriser calculer la factorisation d’un entier naturel n comme produit de nombres
premiers ?
Rappelons d’abord la méthode apprise au lycée, en relation avec le crible d’Ératosthène. Si
n n’est pas premier, il s’écrit comme produit n = k`√avec 2 ≤ k ≤ ` ≤ n − 1. Alors k 2 ≤ n et
donc n est
√ divisible par un entier inférieur ou égal à n. Par conséquent, si aucun
√ des entiers 2,
3, . . ., b nc ne divise n, alors n est premier. L’algorithme exige donc au plus b nc − 1 tests de
divisibilité
et sa complexité mesurée en termes du nombre de tests de divisibilité appartient donc
√
à O( n).
On remarque que cet algorithme n’est que la première étape d’un algorithme de factorisation.
Soit n ≥ 2 un entier. On teste n pour divisibilité d’abord par 2, puis par 3, et ainsi de suite jusqu’à
ce qu’on trouve le plus petit entier p1 ≥ 2 divisant n. Alors 1 est forcément un nombre premier,
et c’est le plus
√ petit nombre premier divisant n. Si n n’est divisible par aucun nombre premier
inférieur à n, on conclut que n est premier. Dans le cas contraire, on calcule le quotient pn1 et on
teste s’il est divisible par p1 . Si n = pr11 n1 avec p1 ne divisant pas n1 , alors le plus petit nombre
premier p2 divisant p1 est strictement plus grand que p1 . On continue de manière récursive, la
factorisation de n étant déduite de celle de n1√
. La récursion s’arrête lorsqu’on trouve un diviseur
n0 de n qui n’est pas divisible par un entier ≤ n0 : on conclut alors que n0 est un nombre premier
et la factorisation de n est terminée.
Proposition. Afin de factoriser
√ l’entier n ≥ 2 par l’algorithme de factorisation qui vient
d’être décrit on a besoin d’au plus n + log2 n tests de divisibilité.
Démonstration. Écrivons la factorisation de n sous la forme
n=
k
Y
pri i ,
p1 < p2 < · · · < pk des nombres premiers et ri > 0 pour tout i ∈ {1, 2, . . . , k}.
i=1
Démonstration. Afin de déterminer p1 , on teste successivement la divisibilité de n par 2, 3, . . .,
p1 − 1 et p1 , ce qui nécessite p1 − 1 tests. Ensuite, la détermination de r1 nécessite r1 − 1 tests de
divisibilité supplémentaires par p1 . Le calcul de p1 , de r1 et de pnr1 nécessite donc (p1 − 1) + (r1 − 1)
1
tests de divisibilité.
De même, si i ≤ k − 1 et si ni−1 = pr1 pr2n···pri−1 , on détermine pi , ri et ni en testant ni−1 pour
1 2
i−1
divisibilité par pi−1 + 1, pi−1 + 2, . . ., pi , puis par ri − 1 tests de division par pi . Cela nécessite
(pi − pi−1 + 1) + (ri − 1) tests de divisibilité.
√
√
Remarquons que si k > 1, alors pi < n pour tout i ≤ k − 1. En effet, si pk−1 ≥ n, alors
pk pk−1 > p2k−1 ≥ n ce qui est absurde.
Dans le cas i√
= k il y a deux donc possibilités :—
(a) Si pk ≤ n, alors le calcul de pk et de rk nécessite (pk − pk−1 + 1) + (rk − 1) tests de
divisibilité. Le nombre total de tests de divisibilité est donc
(p1 − 1) + (r1 − 1) +
k
X
k
X
√
(pi − pi−1 + 1) + (ri − 1) = pk − 2 +
ri ≤ n + log2 n.
i=2
i=1
52
√
(b) Si pk > n, alors rk = 1 et on√en tire que nk−1 = pk . On se trouve √
dans ce cas si aucun
des nombres pk−1 + 1, pk−1 + 2, . . ., b nc ne divisent nk−1 . Cela nécessite b nc − pk−1 + 1 tests
de divisibilité. Le nombre total de tests de divisibilité est donc
(p1 − 1) + (r1 − 1) +
k−1
X
k
X
√
√
(pi − pi−1 + 1) + (ri − 1) + (b nc − pk−1 + 1) = b nc − 2 +
ri
i=2
i=1
Dans les deux cas, on conclut que le nombre de tests de divisibilité est au plus
Mais comme pi ≥ 2 pour tout i, on a
P
√
n + ki=1 ri .
2r1 +r2 +···+rk = 2r1 2r2 · · · 2rk ≤ pr11 pr22 · · · prkk = n,
d’où
Pk
i=1 ri
≤ log2 n
√
Le nombre de tests de divisibilité nécessaires pour factoriser n appartient donc à O( n) ; en
tenant compte de la complexité
des tests de divisibilité, on arrive à un algorithme dont le com√
plexité appartient à O( n(log n)2 . Les meilleurs algorithmes connus actuellement pour factoriser
1 +ε
un entier n ont une complexité heuristique appartenant à O(e(log n) 2 ) pour tout ε > 0. Nous ne
connaissons donc pas, actuellement, un algorithme de complexité polynômiale de factorisation,
c’est-à-dire dont la complexité appartient à O((log n)c ) pour une certaine constante c > 0.
Le teste de primalité de Miller-Rabin
Par contre, nous connaissons des tests de primalité qui, vu comme algorithmes probabilistes,
ont une complexité polynômiale en moyenne. Après quelques préliminaires, nous présenterons le
test de primalité de Miller-Rabin.
Commençons en rappelant le petit théorème de Fermat.
Proposition. Soit n ≥ 1 un nombre premier et soit a un entier premier à n. Alors
an−1 ≡ 1 (mod n).
On en tire le corollaire suivant :
Corollaire. Soit n ≥ 1 un entier. S’il existe un entier a premier à n tel que an−1 6≡ 1 (mod n),
alors n n’est pas un nombre premier.
Ce corollaire est parfois appelé le test de Fermat (ou même le test de primalité de Fermat,
ce qu’il n’est sûrement pas). Pour montrer que n n’est pas premier, on choisit au hasard un entier
a premier à n et on calcule an−1 (mod n). Si après un certain nombre d’essais, on trouve a tel que
an−1 ≡ 1 (mod n), on conclut que a n’est pas premier. Notons que si on choisit a entre 1 et n − 1,
alors la complexité du calcul de pgcd(a, n) appartient à O((log n)2 ), puis le calcul de an−1 (mod n)
par exponentiation rapide appartient à O((log n)3 ). Le test peut alors être effectué en complexité
polynômiale en log n.
Que conclure si on ne trouve pas a premier à n tel que an−1 6≡ 1 (mod n) ? On en peut pas
conclure que n est premier, car il existe des entiers n ≥ 2 qui ne sont pas premiers mais qui
vérifiant an−1 ≡ 1 (mod n) pour tout entier a premier à n. Un tel entier s’appelle un nombre de
Carmichael. Le plus petit nombre de Carmichael est 561 (voir l’Exercice 1 de la feuille 9).
53
On a le raffinement suivant du petit théorème de Fermat :
Théorème. Soit n ≥ 3 un nombre premier impair. On écrit n − 1 = 2t u, avec t ≥ 1 et u
impair. Soit a un entier premier à n. Alors ou bien
(i) au ≡ 1 (mod n), ou bien
m
(ii ) il existe un entier m tel que 0 ≤ m ≤ t − 1 et a2 u ≡ −1 (mod n).
Démonstration. Puisque n est un nombre premier, (Z/nZ)× est un groupe d’ordre n − 1.
D’après le théorème de Lagrange, l’ordre de la classe de a (mod n) divise n − 1 ; il s’écrit donc 2r v
avec 0 ≤ r ≤ t et v un entier impair qui divise u.
Supposons que r = 0. Alors av ≡ 1 (mod n) d’où au ≡ 1 (mod n), car v divise u. On est alors
dans le cas (i).
r−1
r
Supposons que r ≥ 1, alors (a2 v )2 ≡ a2 v ≡ 1 (mod n) et, Z/nZ étant un corps, on a ou
r−1
r−1
bien a2 v ≡ 1 (mod n) ou bien a2 v ≡ −1 (mod n). La première possibilité est exclue, car 2r v
est l’ordre de la classe de a. Par conséquent, si on pose m = r − 1, on a 0 ≤ m ≤ t − 1 et, comme
v divise u et v et u sont impairs,
mu
a2
m
u
u
≡ (a2 v ) v ≡ (−1) v ≡ −1 (mod n).
On se trouve alors dans le cas (ii ).
Le théorème permet de montrer que 561 n’est pas un nombre premier. Notons que 560 = 24 ×35
et prenons par exemple a = 2. On trouve 235 ≡ 263 (mod 561), de sorte que la conclusion (i ) n’est
pas vérifiée. De même, 270 ≡ 263 (mod 561), 2140 ≡ 166 (mod 561), et 2280 ≡ 67 (mod 561), et la
conclusion (ii ) n’est pas vérifiée.
Soit n ≥ 3 un entier impair et soit a un entier. On écrit n − 1 = 2t u, avec t ≥ 1 et u un entier
impair. Si n n’est pas premier, alors on dit que n est un nombre pseudopremier fort en base
a, si l’une des deux conditions (i ), (ii ) du théorème précédent est satisfaite, c’est-à-dire si ou bien
m
(i ) au ≡ 1 (mod n), ou bien (ii ) il existe un entier m tel que 0 ≤ m ≤ t − 1 et a2 u ≡ −1 (mod n).
Théorème (Monier, Rabin). Soit n ≥ 3 un entier impair. On suppose que n ne soit pas premier et on note S(n) le nombre d’entiers a ∈ {1, 2, . . . , n} tels que n est un nombre pseudopremier
fort en base a. Alors S(n) ≤ 41 ϕ(n), où ϕ est la fonction indicatrice d’Euler.
On trouvera une démonstration de ce résultat dans le chapitre 3 du livre Prime Numbers, a
Computational Perspective de R. Crandall et C. Pomerance.
Le théorème de Monier et Rabin montre que, si n ≥ 3 n’est pas premier, pour plus de trois
quarts des entiers a entre 1 et n−1 et premiers à n, n n’est pas un pseudopremier fort en base a. En
supposant que les bases a de pseudoprimalité de n sont uniforément distribuées dans l’intervalle
[1, n − 1], on conclut que, si n n’est pas premier et si a ∈ {1, 2, . . . , n − 1} est choisi au hasard, la
probabilité que n soit un pseudopremier fort en base a est au plus 14 .
Le test de primalité de Miller-Rabin consiste donc en choisissant au hasard une séquence
d’entiers a dans l’intervalle [1, n − 1] et en testant si n vérifie les deux conditions (i ) et (ii ). Un
tel test s’appelle un test de Miller-Rabin. Si k entiers a sont ainsi testés et tous vérifient les
deux conditions, on déclare que n est premier avec un probabilité d’au moins 1 − 41k .
Remarques. (1) À vrai dire, l’appelation test de primalité est, sur le plan logique, impropre,
car il s’agit d’un test qui, en cas d’echec, prouve que n n’est pas premier, mais dont le succès ne
garantit pas que n soit premier.
(2) Sous une version étendue de l’hypothèse de Riemann, on peut montrer que, si n n’est pas
premier, alors il existe au moins un entier a < 2(log n)2 pour lequel n n’est pas un pseudopremier
54
fort en base a. Ainsi, si tous les entiers a inférieurs à cette borne vérifient les conditions (i ) et (ii ),
alors n est premier. Ainsi, on aurait un test déterministe de primalité en complexité polynômiale.
(3) En fait, il existe un test déterministe de primalité en complexité polynômiale, le test
d’Agrawal, Kayal et Saxena (AKS). En pratique, il est peu implémenté car moins beaucoup moins
rapide que le test de Miller-Rabin.
(4) Le test de Miller-Rabin est très utilisé pour construire des nombres premiers de taille
cryptographique , c’est-à-dire ayant, grosso modo, entre 192 et 4096 bits. Typiquement, entre 20
et 60 entiers a sont testés. Ainsi, les nombres premiers utilisés en cryptographie ne le sont, parfois,
qu’avec une probabilité d’au moins 1 − 4120 soit environ 1 − 10112 . . ..
(5) Un nombre RSA est un entier naturel qui est le produit de deux nombres premiers
distincts mais à peu près de la même taille. Les protocols cryptographiques RSA sont basés
sur le principe qu’il est facile de fabriquer des nombres RSA mais difficile de les factoriser. En
effet, pour créer un nombre RSA il suffit de trouver deux nombres premiers d’une taille convenable,
puis de calculer leur produit. D’après ce qui précède, cela peut se faire en complexité heuristique
O(log n)5 . Le nombre RSA ainsi crée est alors la clé publique. Mais la factorisation d’un nombre
RSA a une complexité beaucoup plus élevée, ce qui la rend impossible avec les techniques actuelle,
au moins si les deux nombres premiers ont été choisis suffisament au hasard. Ici, R est pour Rivest,
S est pour Shamir et A est pour Adleman.
Étude des racines d’un polynôme à coefficients réels ou complexes : généralités
Dans les sections qui suivent nous allons étudier, d’un point de vue algorithmique, la localisation et l’approximation des racines d’un polynôme à coefficients réels ou complexes. En réalité,
il est extrêmement difficile de construire un algorithme déterministe et efficace pour calculer
numériquement les racines d’un polynôme. Nous nous limiterons à en discuter certains de ces
ingrédients.
Quatre problèmes, de nature assez différentes, apparaissent alors :—
(i ) La localisation des racines. Par localisation des racines, on entend obtenir des informations
générales sur la position des racines (sur la droite réelle ou dans le plan complexe) en fonction des
coefficients ou d’autres propriétés du polynôme. Un problème lié est la détermination du nombre
des racines dans un ensemble donné.
(ii ) La séparation des racines. Par séparation des racines, on entend la détermination d’une
famille d’ensembles explicites de nombres complexes deux-à-deux disjoints et contenant chacun
une et une seule racine.
(iii ) La recherche d’une première approximation, en principe assez grossière, d’une racine, à
partir des informations obtenues par les méthodes de (ii ). Cela s’effectue à l’aide d’un algorithme
récursif, qui a donc besoin d’une approximation initiale. En général ces algorithmes convergent
assez lentement vers la racine, mais leur convergence est assurée pour un large choix de valeurs
intiales.
(iv ) La recherche d’une approximation précise de la racine à l’aide d’un algorithme à convergence rapide. À nouveau, il s’agit d’un algorithme récursif, mais sa convergence n’est assurée que
si l’approximation initiale appartient à un ensemble plus restreint que les ensembles utilisables
dans les algorithmes de (iii ).
On dispose de méthodes différentes selon que les polynômes sont à coefficients réels ou à
coefficients complexes.
55
Rappelons pour mémoire que le théorème de Gauss-d’Alembert affirme que, si f est un
polynôme de degré n ≥ 1 à coefficients complexes, alors f sécrit de façon unique sous la forme
Y
f (x) = c
(x − ρ)nρ ,
ρ∈Z(f )
où c ∈ C× , Z(f ) est l’ensemble des racines de f et, pour tout ρ ∈ Z(f ), l’entier nρ est la
multiplicité de ρ.
En prenant la dérivée logarithmique, on obtient la formule
X nρ
f 0 (x)
=
,
f (x)
x−ρ
ρ∈Z(f )
qui sera utilisée plus tard.
Q
Par définition, le radical de f est le polynôme ρ∈Z(f ) (x − ρ), c’est-à-dire le polynôme ayant
les mêmes racines que f , mais avec multiplicité un. Puisqu’il est souvent utile de pouvoir se
restreindre aux polynômes sans racines multiples, il est important de savoir calculer le radical de
f sans connaı̂tre les racines de f . Ceci est accompli par le résultat suivant :
Théorème. Soit f ∈ C[x] un polynôme de degré au moins un. On note f 0 la dérivée de f .
Alors, à une constante multiplicative près, le radical de f est égal à
f (x)
.
pgcd(f (x), f 0 (x))
Q
Démonstration. Posons d(x) = pgcd(f (x), f 0 (x)). Il s’agit de montrer que d(x) = ρ∈Z(f ) (x −
ρ)ρa −1 . Puisque d(x) divise f (x), toute racine de d est une racine de f , et il suffit donc vérifier
que la multiplicité de chaque racine ρ de f comme racine de d est égale à nρ − 1. Soit donc
ρ ∈ Z(f ). Alors f (x) = (x − ρ)nρ u(x), où u(x) ∈ C[x] et u(ρ) 6= 0. Par conséquent, f 0 (x) =
(x − ρ)nρ −1 (nρ u(x) + (x − ρ)u0 (x)) et on en tire que (x − ρ)nρ −1 divise f 0 (x) et donc divise aussi
d(x).
Montrons par l’absurde que (x−ρ)nρ ne divise pas d(x). En effet, dans le cas contraire (x−ρ)nρ
f 0 (x)
0
diviserait f 0 (x), et x − ρ diviserait alors (x−ρ)
nρ −1 = nρ u(x) + (x − ρ)u (x). On en tirerait que x − a
diviserait nρ u(x). Or, x − ρ ne divise pas u(x) et nρ ≥ 1, ce qui donne une contradiction.
Remarques (1). Supposons que les coefficients de f appartiennent à un sous-corps K de C.
Alors il en de même pour les coefficients de f 0 . Par conséquent, les coefficients de pgcd(f (x), f 0 (x))
appartiennent également à K et on conclut que le coefficients du radical de f appartiennent encore
à K.
(2). Nous venons de voir que le calcul du radical d’un polynôme f à coefficients complexes se
réduit au calcul du pgcd de f et de sa dérivée f 0 . Par contre, nous ne connaissons aucune méthode
pour calculer le radical d’un entier naturel sans connaı̂tre sa factorisation comme produit de
nombres premiers.
Localisation des racines d’un polynôme
Commençons avec le résultat général suivant :
Théorème. Soit f (x) = f0 + f1 x + · · · + fn−1 xn−1 + xn un polynôme unitaire de degré n ≥ 1
à coefficients complexes. Soit ρ une racine de f .
56
(i ) Soit r > 0 un réel tel que
rn ≥ |f0 | + |f1 |r + · · · + |fn−1 |rn−1 .
Alors |ρ| ≤ r.
(ii ) On pose M = max(|f0 |, |f1 |, . . . |fn−1 |). Alors
|ρ| ≤ 1 + M.
Démonstration. (i ) Supposons pour une contradiction que |ρ| > r. Alors |ρ|n > rn et donc
|f (ρ)| ≥ |ρ|n − |f0 | + |f1 ||ρ| + · · · + |fn−1 ||ρ|n−1
> rn − |f0 | + |f1 |r + · · · + |fn−1 |rn−1
≥ 0,
d’où f (ρ) 6= 0, ce qui est la contradiction cherchée.
(ii ) Puisque M ≥ 0, le résultat est évident si |ρ| ≤ 1. Supposons donc que |ρ| > 1. Puisque ρ
est une racine de f , on a
ρn = −(f0 + f1 ρ + f2 ρ2 + · · · + fn−1 ρn−1 ),
d’où
|ρ|n ≤ |f0 | + |f1 ||ρ| + |f2 ||ρ|2 + · · · + |fn−1 ||ρ|n−1
≤ M 1 + |ρ| + |ρ|2 + · · · + |ρ|n−1
|ρ|n − 1
=M
|ρ| − 1
|ρ|n
≤M
.
|ρ| − 1
Puisque |ρ| > 1, on peut simplifier le |ρ|n , ce qui donne 1 ≤
M
puis |ρ| ≤ 1 + M .
|ρ| − 1
Corollaire. Soit f (x) = f0 + f1 x + · · · + fn−1 xn−1 + xn un polynôme unitaire de degré n ≥ 1
à coefficients réels. Si M = max(|f0 |, |f1 |, . . . , |fn−1 |), alors toutes les racines réelles de f sont
situées dans l’intervalle [−1 − M, 1 + M ].
Le théorème de Rolle affirme comme cas particulier que si ρ1 < ρ2 sont deux racines réelles
d’un polynôme f à coefficients réels de degré n ≥ 1, alors l’intervalle ]ρ1 , ρ2 [ contient une racine de
la dérivée f 0 de f . On en tire que si ρmin et ρmax désignent respectivement la plus grande et la plus
petite racine de f , et si f a n racines réelles distinctes, alors toutes les racines réelles de f 0 sont
réelles et elles appartiennent à l’intervalle ]ρmin , ρmax [. Gauss a découvert un résultat semblable
concernant les racines complexes de la dérivée d’un polynôme à coefficients complexes.
Rappelons que si E est un R-espace vectoriel, un sous-ensemble X de E est dit convexe (ou
un convexe) si, quelque soient x, y ∈ X, le segment droit {(1 − t)x + ty | t ∈ [0, 1]} est contenu
dans X. On voit que toute intersection de convexes de E est convexe. Si X est convexe, si X0 est
un
P sous ensemble fini de X et si {tx | x ∈ X0 } est une famille de nombres réels et positifs telle que
x∈X0 tx = 1, alors
X
tx x ∈ X.
x∈X0
57
Soit Z un sous-ensemble de E. Puisque E est lui-même convexe, l’intersection de tous les
convexes de E qui contiennent Z est un convexe contenant Z, et c’est plus petit convexe contenant
Z. On l’appelle l’enveloppe convexe de Z.
Théorème (Gauss, F. Lucas). Soit f ∈ C[x] un polynôme de degré au moins un. Alors
l’ensemble des racines de f 0 est contenu dans l’enveloppe convexe de l’ensemble des racines de f .
Démonstration. Notons Z(f ) l’ensemble des racines de f . On écrit
Y
f (x) =
(x − ρ)nρ ,
ρ∈Z(f )
où nρ est la multiplicité de la racine ρ. Alors
X
f 0 (x)
nρ
=
.
f (x)
x0 − ρ
ρ∈Z(f )
Soit alors x0 une racine de f 0 . Le résultat est évident si x0 est également une de f . Supposons
donc que cela ne soit pas le cas. Alors
0=
X
X nρ (x̄0 − ρ̄)
f 0 (x0 )
nρ
=
=
,
f (x0 )
x0 − ρ
|x0 − ρ|2
ρ∈Z(f )
d’où
X
ρ∈Z(f )
ρ∈Z(f )
X
nρ ρ̄
nρ x̄
=
.
0
2
|x0 − ρ|
|x0 − ρ|2
ρ∈Z(f )
En prenant le conjugué complexe en en divisant par
X
ρ∈Z(f )
x0 =
X
tρ ρ,
nρ
, on trouve une égalité
|x0 − ρ|2
où tρ ≥ 0 pour tout ρ ∈ Z(f ) et
ρ∈Z(f )
X
tρ = 1,
ρ∈Z(f )
d’où le résultat.
Séparation des racines réelles d’un polynôme à coefficients réels
Dans ce paragraphe, on considère des polynômes à coefficients complexes. Comme précédemment, on note f 0 la dérivée de f et par Z(f ) l’ensemble des racines complexes de f . On note ZR (f )
l’ensemble de ses racines réelles.
Diverses méthodes, en commençant par Descartes, ont été élaborées pour déterminer le nombre
de racines réelles de f appartenant à un intervalle ]a, b[, où a < b appartiennent à R ∪ {−∞, +∞}.
Nous nous limiterons ici au théorème de Sturm, en suivant la présentation dans F. Gantmacher,
Théorie des matrices, Vol II, chapitre 15, § 2. En remplaçant le polynôme par son radical, il suffit
de traiter le cas où les racines de f sont deux-à-deux distinctes.
Soit R ∈ R(x) une fonction rationnelle, c’est-à-dire le quotient de deux polynômes à coefficients
réels. On suppose que R 6= 0. Si ρ ∈ C, alors il existe un unique entier νρ tel que la limite
limx→ρ (x − ρ)−νρ R(x) est finie et non-nulle. On dit que a est un pôle de R si νρ > 0, et l’entier
58
νρ s’appelle alors l’ordre du pôle ρ de R. Les pôles de R sont en nombre fini, car tout pôle est
forcément une racine du polynôme dénominateur de R. On peut alors écrire
R(x) =
Pρ (x)
+ R1 (x),
νρ
(x
−
ρ)
ρ pôle réel
X
où la somme parcourt l’ensemble des pôles réels de R et la fonction rationnelle R1 (x) est sans pôle
réel. Ici, le polynôme Pρ est de degré au plus νρ − 1 et ne s’annule pas en a. Si a < b sont deux
éléments de R ∪ {−∞, +∞}, on appelle alors indice de Cauchy de R sur ]a, b[ l’entier
X
Iab (R) =
sign(Pρ (ρ)),
a<ρ<b
νρ impair
où sign(u) ∈ {0, −1, 1} désigne le signe du nombre réel u. La somme parcourt tous les pôles d’ordre
impair appartenant à l’intervalle ouvert ]a, b[.
Si par exemple f ∈ R[x] est un polynôme non nul, alors on a
X
f 0 (x)
nρ
=
+ R1 (x),
f (x)
x−ρ
ρ∈ZR (f )
où à nouveau R1 est sans pôle réel et nρ est la multiplicité de la racine ρ de f . Puisque nρ > 0
pour tout ρ ∈ Z(f ), on constate que Iab (f 0 /f ) est égal au nombre de racines réelles de f situées
dans l’intervalle ]a, b[.
En général, si ρ est un pôle réel de R, Iab (R) mesure la contribution des pôles au nombre de
changements de signe de R(x) lorsque x parcourt ]a, b[. Rappelons que ρ est un pôle de R et si νρ
est pair, alors R(x) a le même signe les deux côtés de ρ, alors que si νρ est impair, R(x) change
de signe lorsque x passe par ρ. C’est pour cette raison que dans la définition de Iab (R), la somme
est restreinte aux pôles d’ordre impair.
Par définition, une suite de Sturm sur ]a, b[ est une famille finie de polynômes (f1 , f2 , . . . , fm )
à coefficients réels telle que :
(1) Pour tout x ∈]a, b[, si k ∈ {2, 3, . . . , m − 1} est un indice tel que fk (x) = 0, alors fk−1 (x)
et fk+1 (x) sont non nuls et de signes opposés ;
(2) On a fm (x) 6= 0 pour tout x ∈]a, b[.
Si (f1 , f2 , . . . , fm ) est une suite de Sturm et si x ∈]a, b[, on note V(f1 ,f2 ,...,fm ) (x) (ou tout
simplement V (x)) le nombre de changement de signe dans la séquence f1 (x), f2 (x), . . ., fm (x),
les termes nuls ayant été supprimés. Remarquons que le signe de la valeur d’un polynôme en x
reste constant lorsque x est assez grand. On définit alors V (+∞) comme étant la valeur de V (x)
lorsque x est assez grand et V (−∞) de façon semblable.
Théorème (Sturm). Soit (f1 , f2 , . . . , fm ) une suite de Sturm sur ]a, b[. Alors
Iab (f2 /f1 ) = V (a) − V (b).
Démonstration. On considère les fonctions x 7→ Iax (f2 /f1 ) et x 7→ V (a) − V (x) lorsque x
parcourt l’intervalle ]a, b[. D’après la définition de Iab , la fonction x 7→ Iax (f2 /f1 ) est constante sur
tout intervalle ouvert ne contenant pas de pôle de f2 /f1 , c’est-à-dire une racine de f1 . D’autre part,
la valeur de V (x) ne peut changer que lorsque x passe par une valeur x0 pour laquelle il existe un
indice k tel que fk (x) = 0. Or, la condition (2) implique que k < m et la condition (1) implique
59
que si k ∈ {2, 3, . . . , m − 1}, alors V (x) ne change pas lorsque x passe par x0 . Par conséquent,
V (x) ne peut changer que lorsque x passe par une racine de f1 . En particulier, Iax (f2 /f1 ) = 0
et V (x) = V (a) lorsque x se trouve dans l’intervalle situé entre a et la plus petite racine de f1
supérieure à a. Par conséquent,
Iax (f2 /f1 ) = V (a) − V (x)
pour tout x > a et suffisament proche de a. Pour conclure la démonstration, il suffit de vérifier
que Iax (f2 /f1 ) et −V (x) changent de la même façon lorsque x augmente en passant par une racine
de f1 .
La condition (1) appliquée avec k = 2 signifie que si ρ est une racine de f1 , alors f2 6= 0 : on en
tire que l’ensemble des pôles de f2 /f1 est égal à l’ensemble des zéros de f1 , et que la multiplicité
de ρ en tant que pôle de f2 /f1 est égale à la multiplicité de ρ en tant que racine de f1 .
Si la multiplicité de ρ est paire, alors les signes de f1 et de f2 /f1 ne changent pas lorsque x
passe par ρ. Par conséquent, ni Iax (f2 /f1 ) ni V (x) ne sont modifiés.
Si la multiplicité de ρ est impaire, alors les signes de f2 /f1 et de f1 changent lorsque x passe
par ρ. Supposons que Pρ (ρ) > 0. Alors Iaρ+ε (f2 /f1 ) = Iaρ−ε (f2 /f1 ) + 1 pour tout ε > 0 suffisament
petit. En plus, f2 (ρ − ε)/f1 (ρ − ε) < 0 et f2 (ρ + ε)/f1 (ρ + ε) > 0. Par conséquent, f1 (ρ − ε) et
f2 (ρ − ε) sont de signes opposés alors f1 (ρ + ε) et f2 (ρ + ε) ont le même signe lorsque ε > 0
est suffisament petit. La suite de Sturm perd alors un changement de signe au début, et −V (x)
augmente par 1 tout comme Iax (f2 /f1 ). Un argument semblable montre que lorsque Pρ (ρ) < 0,
Iax (f2 /f1 ) et −V (x) diminuent par 1. D’où le résultat.
Pour que ce résultat puisse être utile, il faut savoir construire une suite de Sturm dont les
deux premiers termes sont f1 et f2 .
Proposition. Soient f1 , f2 deux polynômes qui ne s’annulent pas simultanément sur ]a, b[. Si
deg(f2 ) ≤ deg(f1 ), alors il existe une suite de Sturm dont les deux premiers termes sont f1 et f2 .
Démonstration. On construit f3 , f4 , . . ., par une variante de l’algorithme d’Euclide : −f3 est
le reste de la division de f1 , par f2 , −f4 est le reste de la division de f2 par f3 , et ainsi de suite.
Alors les degrés successifs deg f2 , deg f3 , deg f4 , . . . décroissent strictement : il existe donc un entier
m ≥ 2 tel que fm 6= 0 mais fm+1 = 0. Si fm s’annule en x0 ∈]a, b[, on voit en remontant que tous les
fk s’annulent en x0 , ce qui contredit l’hypothèse que f1 et f2 ne s’annulent pas simultanément. De
même, si fk (x0 ) = 0, alors fk−1 (x0 ) = −fk+1 (x0 ) est non-nul, car si fk−1 (x0 ) = 0, alors f` (x0 ) = 0
pour tout ` ∈ {1, 2, . . . , m}, contrairement aux hypothèses.
On peut utiliser le théorème et la proposition pour calculer le nombre de racines réelles d’un
polynôme f à coefficients réelles dans différents intervalles. On suppose que f est sans racine
multiple, ce qui équivaut à f et f 0 n’ayant pas de facteur en commun. On forme alors la suite
de Sturm dont les premiers termes sont f1 = f , f2 = f 0 selon la recette de la proposition. On
remarque que fm est un pgcd de f1 et de f2 , qui sera donc sous nos hypothèses une constante non
nulle.
Séparation des racines : cas d’un polynôme à coefficients complexes
Le problème de la séparation des racines complexes est nettement plus délicat que celui de
la séparation des racines réelles. Nous nous limiterons donc à signaler quelques pistes, sans les
approfondir, et qui peuvent êgalement être appliquées aux polynômes à coefficients complexes.
60
Soit donc f (x) ∈ C[x] un polynôme non nul. Alors f est une fonction analytique, et si γ est
un lacet dans le plan complexe, alors
Z 0
1
f (z) dz
2πi γ f (z)
est un entier relatif qui, dans des cas simples, est égal à la somme des résidus des pôles de f 0 /f
situés dans la région D du plan complexe dont γ est le bord. C’est le cas notamment lorsque
γ(t) = a + re2πit (où t ∈ [0, 2π]) paramètre un cercle, ou γ est une fonction affine par morceaux
paramétrant les côtés successifs d’un rectangle. Or, la décomposition
X nρ
f 0 (x)
=
f (x)
x−ρ
ρ∈Z(f )
montre que les pôles de f 0 /f sont tous simples, situés aux racines de f , et que le résidu d’un pôle
est égal à la multiplicité de la racine correspondante. On en tire le résultat suivant.
Proposition. Soit γ un lacet simple, bordant le domaine D. Alors
Z 0
X
1
f (z) dz
=
nρ .
2πi γ f (z)
ρ∈D∩Z(f )
Autrement dit, l’intégrale calcule le nombre de racines de f situées dans D, comptées avec
multiplicité. Une stratégie pour déterminer ce nombre sera alors le calculer une valeur approchée
de l’intégale par des méthodes d’intégration numérique.
Un problème intéressant, et important notamment dans la théorie des équations différentielles,
est de donner des conditions sur un polynôme pour que toutes ses racines soit de partie réelle
négative. Plus généralement, on peut chercher à compter le nombre de racines dont la partie
réelle est négative, ou dont la partie réelle appartient à un demi-plan donnée. C’est le problème
de Routh-Hurwitz, qui est traité dans le chapitre 15 du livre de Gantmacher déjà cité. Une
approche est de prendre pour γ le lacet formé par un segment de longueur r > 0 de la demi-droite
bordant le demi-plan, suivi par le demi-cercle du même rayon qui retourne au point de départ,
puis de faire tendre r → +∞.
Recherche d’une première approximation d’une racine
Nous arrivons donc au problème (iii ) de notre étude des racines d’un polynôme, à savoir
trouver une première approximation suffisament proche d’une racine pour que les méthodes d’approximation rapide, qui seront discutées dans la section suivante, puissent être appliquées. Ici, la
méthode la plus simple est d’utiliser le principe de recherche par dichotomie.
Considérons d’abord le cas d’un polynôme f à coefficients réels. Si a et b sont deux réels tels
que f (a)f (b) ≤ 0, alors le théorème des valeurs intermédiaires implique que f possède une racine ρ
dans l’intervalle [a, b]. On peut alors chercher une première approximation à une racine ρ contenue
dans l’intervalle en posant ρ1 = a, ρ2 (b). Si f (ρ1 ) = 0 ou si f (ρ2 ) = 0, on a gagné. Sinon, on pose
3
3
ρ3 = a+b
. Si f (ρ3 ) = 0, on a gagné. Sinon, on pose ρ4 = ρ1 +ρ
si f (ρ1 )f (ρ3 ) < 0 et ρ4 = ρ2 +ρ
si
2
2
2
f (ρ2 )f (ρ3 ) < 0. En continuant ainsi obtient une suite (ρn )n≥1 où ρn appartient à un intervalle In
de longueur |b−a|
chacun emboı̂té dans le précédent et dans lequel f prend à la fois des valeurs
2n
61
positives et des valeurs négatives. La suite qui converge vers un élément ρ de [a, b]. On a alors
f (ρ) = 0, car si par exemple f (ρ) > 0, alors la continuité de f entraı̂nerait que f prend des valeurs
strictement positives sur un intervalle ouvert J contenant ρ. Mais In ⊆ J pour tout n assez grand,
ce qui est contredirait le fait que f change de signe sur In .
Il est clair que ρn est une valeur approchée de ρ avec une erreur d’au plus |b−a|
. Autrement
2n
dit, la qualité de l’approximation augmente linéairement avec n. Si par exemple, on travaille en
base 10, on gagne un chiffre décimal après un nombre constant d’itérations.
Remarquons que la condition f (a)f (b) ≤ 0 à elle seule n’entraı̂ne pas l’unicité de la racine ρ
dans l’intervalle [a, b]. Cela sera assuré si, par exemple f est monotone sur [a, b], ce qui sera le
cas par exemple si la dérivée de f est de signe constante sur [a, b], une condition qui peut être
appréciée en appliquant le théorème de Sturm à f 0 .
Une principe semblable peut être appliquée pour approximer les racines complexes d’un polynôme à coefficients complexes. On suppose pour simplifier que f soit unitaire et sans racine
multiple. Soit M le maximum des valeurs absolues des coefficients de f . On sait alors que toute
racine ρ de f vérifie |ρ| ≤ 1 + M .
Soit alors γ1 le carré centré à l’origine du plan complexe et dont les côtés sont de longueur
1 + M et parallèles aux axes réels et imaginaires. On sait alors que
Z
1
f 0 (z) dz
= deg f,
2πi γ1 f (z)
l’intégrale étant prise en contourant l’origine dans le sens contraire des aiguilles d’une montre.
Si on partitionne la région bordée par γ1 en quatre parties égales, onR obtient
quatre régions
f 0 (z) dz
1+M
1
chacune bordée par un carré de côté 2 . En calculant l’intégrale 2πi
sur chacun de
f (z)
ces quatres carrés, on obtient la répartition des racines entre les quatre régions. En partionnant
chacune de ces quatres régions de la même manière à son tour, on obtient la répartition des racines
entre les seize régions. En partionnant encore, on trouve au bout d’un certain temps deg f carrés
contenant chacun une et une seule racine de f , les autres carrés ne contenant aucune racine de
f . Soit ρ une racine de f . En partionnant encore le carré contenant ρ de la même maniére, et en
notant ρn le centre du carré obtenu après n itérations, on voit que la suite (ρn ) converge vers ρ et
.
que max(|Re(ρn − ρ)|, |Im(ρn − ρ)|) ≤ 1+M
2n
À nouveau donc, la qualité de l’approximation augment linéairement avec n.
Comme remarqué précédement, les intégrales peuvent être calculés par des méthodes d’intégration numérique. Par ailleurs, dans cette discussion, nous avons laissé à côté la possibilité que
f possède une racine sur le bord de l’une des carrés ou même proche du bord de l’un des carrés,
car cela engendre de l’instablilité numérique dans l’évaluation de l’intégrale. Ce problème va de
toute façon se rencontrer lorsque n augmente.
Une méthode de pallier ce problème et de remplacer le calcul de l’intégral par l’étude des
polynômes réels Re(f ) et Im(f ), vus comme fonction des deux variables réelles x = Re(z) et
y = Im(z). Sur chacun des côtés des carrés, qui sont parallèles aux axes réel et imaginaire, l’une
de ces variables est en fait constante, et on y est ramené à l’étude d’un polynôme à coefficients
réels en une seule variable réelle. Si K est un tel carré dont l’intérieur contient une unique racine
simple ρ, on peut montrer, si K est suffisament petit, que la courbe décrite implicitement par
l’équation Ref (x, y) = 0 coupe le bord du carré en deux points, qui alternent avec les deux points
d’intersection du bord avec la courbe implicite Imf (x, y) = 0. Par contre, si K ne contient pas ρ,
une telle configuration des points d’intersection ne peut pas se produire. Ainsi, si on divise K en
quatre carrés, une connaissance des configurations des points d’intersection de Ref (x, y) = 0 et
de Imf (x, y) = 0 avec les quatre petits carrés permet de déterminer lequel contient ρ.
62
Approximation rapide d’une racine, la méthode de Newton
La méthode de Newton d’approcher une racine simple ρ du polynôme f est résumée par la
0)
phrase : si x0 est une première approximation de ρ, alors x0 − ff0(x
devrait en être une meilleure.
(x0 )
Cette idée a sans doute déjà été rencontrée dans le cadre de fonctions dérivables d’une variable
réelle. Elle a également un sens pour les fonctions analytiques d’une variable complexe ; dans ce
cas f 0 (x0 ) signifie la dérivée en x0 par rapport à la variable complexe.
L’utilité de la méthode de Newton peut être résumée par le fait que si la première l’approxi0)
mation x0 de ρ est déjà très proche de ρ, alors la nouvelle approximation x1 = x0 − ff0(x
vérifie
(x0 )
|x1 − ρ| ≤ |x0 − ρ|2 ,
ce qui signifie que la convergence est quadratique c’est-à-dire qu’à chaque itération, le nombre
de chiffre décimaux correcte est à peu près doublé. Cela se voit déjà de manière frappante sur
l’exemple où f (x) = x2 − 2. À partir de ρ0 = 1, la suite des approximations (ρn ) est définie pour
n ≥ 1 par
f (ρn−1 )
1
2 ρn = ρn−1 − 0
=
ρn−1 +
.
f (ρn−1 )
2
ρn−1
Alors
3
17
577
665857
886731088897
ρ0 = 1, ρ1 = , ρ2 = , ρ3 =
, ρ4 =
, ρ5 =
, ...
2
12
408
470832
627013566048
√
n−1
On constate que |ρn − 2| ≤ 10−2
lorsque n ∈ {1, 2, 3, 4, 5} et, en fait si n ≥ 1,
√
√
√
√
ρ2n−1 − 2 2ρn−1 + 2
(ρn−1 − 2)2
ρn − 2 =
=
≤ (ρn−1 − 2)2
2ρn−1
2ρn−1
√
n−1
car 1 ≤ ρn ≤ 2 pour tout n. On en déduit par récurrence sur n que |ρn − 2| ≤ 10−2
pour tout
n ≥ 1.
Le résultat suivant implique des conditions suffisantes pour que la suite (ρn ) des approximations de ρ définies à partir d’une valeur initiale ρ0 = z converge vers la racine ρ.
Théorème. Soit f une fonction analytique sur domaine contenant le disque fermé D de centre
ρ et de centre r > 0. Soit m1 et M2 deux réels strictement positifs. On suppose que
(a) f (ρ) = 0,
(b) |f 0 (z)| ≥ m1 pour tout z ∈ D,
(c) |f 00 (z)| ≤ M2 pour tout z ∈ D.
Pour tout z ∈ D, on pose w = z − ff0(z)
.
(z)
(i ) On suppose que 3M2 r ≤ m1 . Alors
1
|w − ρ| ≤ |z − ρ|.
2
(ii ) On suppose que A > 0 vérifie 3M2 ≤ 2m1 A. Alors
|w − ρ| ≤ A|z − ρ|2 .
Démonstration. Quitte à effectuer une translation, on peut supposer que ρ = 0, de sorte que
f (0) = 0. Alors
f 0 (z)w = f 0 (z)z − f (z) = f 0 (0)z − f (z) + (f 0 (z) − f 0 (0))z.
63
Or, D étant étoilé par rapport à l’origine, la formule de Taylor d’ordre deux implique que |f 0 (0)z −
f (z)| ≤ M22 |z|2 pour tout z ∈ D. De même, la formule de Taylor d’ordre d’ordre un appliquée à f 0
implique que |f 0 (z) − f 0 (0)| ≤ M2 |z| pour tout z ∈ D. Par conséquent,
m1 |w| ≤ |f 0 (z)w| = | f 0 (0)z − f (z) + (f 0 (z) − f 0 (0))z|
≤ |f 0 (0)z − f (z)| + |(f 0 (z) − f 0 (0))z|
3M2 2
M2 2
|z| + M2 |z|2 =
|z| .
≤
2
2
Afin de montrer le (i ), on remarque que |z|2 ≤ r|z|, d’où m1 |w| ≤ 3M22 r |z| puis |w| ≤
Le (ii ) se démontre d’une manière semblable grâce à l’hypothèse 3M2 ≤ 2m1 A.
3M2 r
2m1
≤ 12 |z|.
Corollaire. On reprend les notations et les hypothèses du théorème. Si ρ0 vérifie |ρ0 − ρ| ≤
m1
n−1 )
, alors la suite (ρn )n≥0 définie à partir de ρ0 par ρn = ρn−1 − ff0(ρ
r ≤ 3M
converge vers ρ.
(ρn−1 )
2
Démonstration. C’est clair, car le (i ) du théorème implique que |ρn − ρ| ≤
r
2n
pour tout n. On utilise le (ii ) du théorème pour justifier que la méthode e Newton converge quadratiquement à partir d’un certain rang. En effet, on peut supposer A > 1, car l’hypothèse 3M2 ≤ 2m1 A
n’est pas modifiée si on augmente A. Soit alors n0 un indice tel que |ρn0 − ρ| ≤ A1 . Alors pour tout
k ≥ 1, on a
k
k
|ρn0 +k − ρ| ≤ Ak |ρn0 − ρ|2 ≤ Ak−2 → 0.
En prenant A =
chaque itération.
1
,
10
on voit que le nombre de chiffres décimaux corrects est presque doublé à
Voici une autre application de la méthode de Newton. Soit a > 0 un réel. À partir du
développement en base 10 de a, on cherche à calculer le développement en base 10 de a1 . On
utilise alors la fonction f (x) = x1 − a. La suite de la méthode de Newton vérifie la relation de
récurrence ρn = 2ρn−1 − aρ2n−1 . Ainsi, le calcul de a1 est réduit à une suite de multiplications.
Cette même méthode peut être appliquée pour calculer l’inverse d’une série formelle. Il y aussi
une application à la division euclidienne avec reste des polynômes qui, utilisée en conjonction
avec la transformée de Fourier rapide, fournit un algorithme algorithme plus rapide que l’algorithme usuel décrit plus tôt dans ce cours. (Voir l’Exercice 4 de la feuille 7).
Notons enfin que si ρ est une racine du polynôme f , l’ensemble des ρ0 ∈ C qui sont les termes
initiaux d’une suite de la méthode de Newton qui converge vers ρ peut être très complexe sur le
plan géométrique. Ce sont des exemples de fractales.
En suivant successivement les quatre étapes de l’étude des racines d’un polynôme (voir la
page 55), on obtient une méthode qui, dans la pratique, permet de calculer les valeurs numériques
des racines d’un polynôme à coefficients réels ou complexes avec une précision élevée. Mais il
est difficile d’en faire un algorithme précis, le problème le plus important se situant au niveau
de l’estimation du nombre d’étapes nécessaires pour séparer les racines et initier les méthodes
d’approximation. La raison est l’absence d’une minoration satisfaisante de la différence entre deux
racines distinctes d’un polynôme. Pour obtenir un algorithme déterministe dont la complexité
peut être calculée, d’autres techniques doivent être introduites.
Annexe : démonstration de la formule d’encadrement de n!.
64
Il s’agit de démontrer le résultat suivant.
Théorème. Pour tout entier n ≥ 1, on a :
n n √
n n √
1/(12n+1)
2πn e
≤ n! ≤
2πn e1/12n .
e
e
La fonction exponentielle étant une fonction croissante, il suffit de démontrer l’inégalité
n+
1
1
1
1
1
1
log n − n + log 2π +
≤ log n! ≤ n +
log n − n + log 2π +
.
2
2
12n + 1
2
2
12n
Commençons par le lemme suivant :
R k+1
Lemme. Pour tout entier k ≥ 1, on pose Ck = k log t dt − 21 log (k + 1) + log k . Si n ≥ 1
est un entier, alors
n−1
X
1
log n! = n +
log n − n + 1 −
Ck .
2
k=1
donc que n ≥ 2. Alors
R k+1Démonstration du lemme. L’égalité est claire lorsque n = 1. Supposons
1
log t dt = (k + 1) log (k + 1) − k log k − 1 et donc Ck = (k + 2 ) log (k + 1) − (k + 12 ) log k − 1,
k
Pn−1
P
(n + 12 ) log n − nk=2 log k − (n − 1) et l’égalité en découle aussitôt en utilisant la
d’où k=1 Ck = P
formule log n! = nk=2 log k.
Pour conclure la démonstration du théorème, il suffit donc de démontrer que
1−
n−1
X
Ck → log
√
2π
lorsque n → +∞
k=1
(et, en particulier, que la série
P∞
k=1
Ck converge) et que
∞
X
1
1
Ck <
<
12n + 1 k=n
12n
quelque soit n.
Commençons par le deuxième point. Après calcul, on trouve
Z k+1
1 + x
1
1
1
1
log (k + 1) + log k = k +
log 1 +
−1=
log
−1
Ck =
log t dt −
2
2
k
2x
1−x
k
où x = 1/(2k + 1).
Puisque
log
1 + x
1−x
lorsque |x| < 1, on a
Ck =
= 2(x +
∞
X
p=1
x3 x5
+
+ ···)
3
5
1
(2p + 1)(2k + 1)2p
ce que l’on peut majorer par
∞
X
p=1
∞
X
1
1
1
1
1 1
1 =
=
=
−
3(2k + 1)2p
3(2k + 1)2 p=0 (2k + 1)2p
12k(k + 1)
12 k k + 1
65
et minorer par
∞
X
1
p=1
3p (2k + 1)2p
∞
X
1
1 1
1
1
1
>
=
=
1 −
2
p
2p
2
3(2k + 1) p=0 3 (2k + 1)
12k + 12k + 2
12 k + 12
k+1+
Par conséquent,
1
12
.
∞
X
1
1
1
1
=
<
,
Ck <
1
12n + 1
12 n + 12
12n
k=n
comme prévu.
P
Il s’ensuit que ∞
k=1 Ck converge et, en prenant l’exponentielle, que
P∞
√ (∗)
lim n!/ (n/e)n n
existe et vaut e1− k=1 Ck .
n→+∞
√
√ Posons donc K = limn→+∞ n!/ (n/e)n n . Pour conclure il faut montrer que K = 2π. Pour
cela, on utilise la formule de Wallis : si
Z π/2
cosn θ dθ,
Jn =
0
alors Jn > 0 quelque soit n ≥ 0 et la suite (Jn ) est décroissante. En intégrant par parties on
trouve, lorsque n ≥ 2, que :
Z π/2
Z π/2
n
cos θ cosn−1 θ dθ
cos θ dθ =
Jn =
0
0
Z π/2
h
iθ=π/2
n−2
= − (n − 1) cos θ sin θ cos
θ
+ (n − 1)
sin2 θ cosn−2 θ dθ
θ=0
0
Z π/2
= 0 + (n − 1)
(1 − cos2 θ) cosn−2 θ dθ
0
= (n − 1)(Jn−2 − Jn ).
En réarrangeant, on en tire que Jn vérifie la relation de récurrence
n−1
Jn =
Jn−2 ,
pour tout n ≥ 2.
n
Par ailleurs, on a J0 = π2 et J1 = 1. En raisonnant par récurrence, on en déduit les formules
1 · 3 · 5 · · · · · (2n − 1) π
2 · 4 · · · · · (2n)
,
J2n+1 =
,
2 · 4 · · · · · (2n)
2
1 · 3 · 5 · · · · · (2n + 1)
pour tout n ≥ 0 puis, comme J2n+1 < J2n < J2n−1 , que
J2n =
(2 · 4 · · · · · (2n))2
π
(2 · 4 · · · · · (2n − 2))2 (2n)
<
<
.
(3 · 5 · · · · · (2n − 1))2 (2n + 1)
2
(3 · 5 · · · · · (2n − 1))2
Le rapport entre les deux membres extrêmes tend vers 1 ; les membres extrêmes tendent donc
vers π2 et obtient la formule de Wallis :
(2 · 4 · · · · · (2n − 2))2 (2n)
24n (n!)4
=
lim
,
n→+∞
n→+∞ n((2n)!)2
(3 · 5 · · · · · (2n − 1))2
où on déduit l’égalité à droite en multipliant le numérateur et le dénominateur du membre au
milieu par (2 · 4 · · · · · (2n))2 .
n n √
D’après (∗), on a n! = K
nern , avec rn → 0 lorsque n → +∞. En substituant cette
e
formule pour n! et la formule correspondante pour (2n)! dans la √
formule de Wallis et en simplifiant,
2
on trouve que π = K /2. Puisque K > 0, on trouve bien K = 2π.
π = 2 lim
66
Téléchargement