Académique Documents
Professionnel Documents
Culture Documents
Jean-Michel Ferrard
Avant-propos
Ce document vise à la préparation à la nouvelle épreuve d’informatique de l’École Polytechnique.
Les caractéristiques de cette épreuve peuvent être consultées à l’adresse :
http ://www.enseignement.polytechnique.fr/informatique/concours/
Parmi les langages de programmation possibles, on a choisi Maple, dont on n’a utilisé que les fonc-
tionnalités de base, conformément aux demandes des concepteurs de l’épreuve.
Le présent document est consacré à l’algorithme de Horner et à ses variations dans des domaines
parfois inattendus. Voici un bref résumé des différentes thèmes abordés :
– Partie I : Évaluation d’un polynôme
C’est l’aspect le plus classique de l’algorithme de Horner. On voit deux méthodes, dont l’une est
récursive. On s’intéresse aussi à l’évaluation en un point de C d’un polynôme à coefficients réels,
toujours dans le souci de diminuer le nombre d’opérations à effectuer.
– Partie II : Division synthétique
L’algorithme de Horner (évaluation d’un poynôme P en un point α) cache en fait une méthode de
division de P par x − α. Dans cette partie, on voit également comment former (à moindre frais)
la division euclidienne de P par X 2 + αX + β.
– Partie III : Translatés d’un polynôme, dérivées successives
On voit ici comment calculer les coefficients du polynôme P (X + α) à partir de ceux de P (X).
On constate qu’on y arrive par deux algorithmes de Horner imbriqués. Développer P (X + α) c’est
aussi exprimer le polynôme P dans la base des (X − α)k . On en déduit en particulier une méthode
pour calculer simultanément les dérivées successives de P en α.
– Partie IV : Règle des signes de Descartes
Elle donne une indication sur les racines positives ou négatives d’un polynôme. L’utilisation de
translations permet alors de localiser des racines de P sur n’importe quel intervalle.
– Partie V : Méthode de Newton de résolution de P (x) = 0
Elle permet d’approcher une racine réelle du polynôme P . On se sert d’algorithmes de Horner en
parallèle pour calculer simultanément les valeurs de P (x) et de P 0 (x) (voire de P 00 (x).)
– Partie VI : Forme de Newton du polynôme interpolateur
Il s’agit d’écrire ici le polynôme interpolateur d’une famille de points sous une forme qui permet
(entre autres) facilement l’ajout d’un point supplémentaire. L’évaluation de ce polynôme s’effectue
par une forme particulière de l’algorithme de Horner.
– Partie VII : Autour du théorème chinois
Dans cette partie, on voit comment trouver la solution d’un système de congruences. On voit que
des calculs “à la Horner” permettent d’obtenir cette solution en minimisant le nombre d’opérations,
et surtout en limitant la taille des calculs intermédiaires.
– Partie VIII : Algorithmes “compte-gouttes”
Dans cette partie, on étudie et on met en œuvre des méthodes qui permettent d’obtenir rapidement
un grand nombre de décimales des nombres e et π. Là encore, ce sont des calculs “à la Horner”.
Algorithmique avec Maple
Variations sur le schéma de Horner
Énoncé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
I. Évaluation d’un polynôme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
II. Division synthétique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
III. Translatés d’un polynôme, dérivées successives . . . . . . . . . . . . . . . . . . 4
IV. Règle des signes de Descartes . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
V. Méthode de Newton de résolution de P (x) = 0 . . . . . . . . . . . . . . . . . . 6
VI. Forme de Newton du polynôme interpolateur . . . . . . . . . . . . . . . . . . . 6
VII. Autour du théorème chinois . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
VIII. Algorithmes “compte-gouttes” . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Corrigé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
I. Évaluation d’un polynôme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
II. Division synthétique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
III. Translatés d’un polynôme, dérivées successives . . . . . . . . . . . . . . . . . . 16
IV. Règle des signes de Descartes . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
V. Méthode de Newton de résolution de P (x) = 0 . . . . . . . . . . . . . . . . . . 20
VI. Forme du Newton du polynôme interpolateur. . . . . . . . . . . . . . . . . . . 23
VII. Autour du théorème chinois . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
VIII. Algorithmes “compte-gouttes” . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Énoncé
Un polynôme P est représenté par un tableau unidimensionnel T de réels, indicé à partir de 1.
Le type d’un tel tableau est array(numeric).
Un tel tableau, lu dans l’ordre des indices croissants, représente un unique polynôme représenté
lui-même dans le sens des puissances décroissantes.
Par exemple, le tableau T = [3, 0, −5, 2, 1] représente le polynôme P = 3X 4 − 5X 2 + 2X + 1.
On utilisera la fonction size suivante pour calculer la taille d’un tableau unidimensionnel T : c’est
un majorant strict du degré du polynôme P associé à T .
> size:=proc(T::array(numeric))
> RETURN(op(2,op(2,eval(T))));
> end:
Par exemple, les tableaux T et U sont de tailles respectives 5 et 7. Evidemment, ils représentent deux
polynômes qui sont de degrés respectifs 4 et 2.
> T:=array([3,0,-5,2,1]):
> U:=array([0,0,0,0,2,4,1]):
> size(T), size(U);
5, 7
Par commodité, on nommera de la même manière un polynôme P et le tableau qui le représente.
1. Écrire une fonction evalh évaluant P en le réel t, avec la syntaxe evalh(P, t).
Cette valeur sera calculée par un algorithme de Horner itératif.
Indiquer le nombre d’additions et de multiplications nécessitées par cet algorithme. [ S ]
2. Écrire une version récursive de la fonction evalh, avec la même syntaxe d’appel. [ S ]
3. Dans cette question, on cherche à évaluer P (z), où z = x + iy est un nombre complexe.
On suppose que les seules opérations possibles sont l’addition et le produit de nombres réels.
Écrire une fonction evalhc, déduite de la version itérative de evalh pour que evalhc(P, x, y)
renvoie le tableau [x0 , y 0 ] donnant la partie réelle et la partie imaginaire de P (x + iy).
Combien cette méthode nécessite-t-elle d’opérations arithmétiques sur les réels ? [ S ]
4. Écrire une autre version de evalc, plus écononome en opérations sur les réels.
On pensera à la division euclidienne de P par X 2 − 2Re (z)X + |z|2 . [ S ]
4. Écrire une fonction derivs prenant en argument un polynôme P (représenté par le tableau
[an , . . . , a1 , a0 ]) et un réel t, et renvoyant le tableau [P (n) (t), . . . , P 0 (t), P (t)] des dérivées suc-
cessives de P au poit t (par ordre décroissant de l’ordre de dérivation.) [ S ]
On appelle changement de signe dans P tout couple (i, j), avec i < j et :
– Les coefficients ai et aj sont non nuls et de signe contraire.
– Pour tout k tel que i < k < j on a ak = 0.
On observe donc un changement de signe quand deux coefficients non nuls consécutifs de P (ordonné
suivant les puissances croissantes ou décroissantes) sont de signes contraires.
Par exemple, le polynôme P = X 8 − 3X 5 + 2X 4 + X 2 − X − 1 présente 3 changements de signe.
Notons s le nombre de changements de signe de P .
La règle de Descartes affirme que le nombre r de racines réelles strictement positives de P est
inférieur ou égal à s, et plus précisément que la différence s − r est un entier pair.
Par exemple, cette règle permet d’affirmer que le polynôme P = X 8 − 3X 5 + 2X 4 + X 2 − X − 1
possède ou bien trois ou bien une seule racine(s) réelle(s) strictement positive(s).
Appliquée à P (−X), cette règle donne une indication sur les racines réelles strictement négatives.
Avec notre exemple, P (−X) = X 8 + 3X 5 + 2X 4 + X 2 + X − 1 présente un seul changement de signe.
Le polynôme P possède donc exactement une racine réelle strictement négative.
1. Écrire une fonction varsign donnant le nombre de changements de polynôme P . [ S ]
3. La méthode précédente a un défaut : des calculs intermédiaires sont effectués plusieurs fois.
D’autre part, on voit bien qu’il suffit ici de calculer les seuls coefficients d1,k .
Écrire une procédure PNewton calculant le tableau [d1,1 , d1,2 , . . . , d1,n ].
On n’utilisera pas la fonction récursive dij. Au contraire les coefficients d1,k seront calculés par
une méthode itérative. Voici une indication sur les premières étapes du calcul :
– On part du tableau Y = [d1,1 , d2,2 , . . . , dn,n ].
– La première étape transforme ce tableau en [d1,1 , d1,2 , . . . , dj,j+1 , . . . , dn−1,n ].
– L’étape suivante conduit à [d1,1 , d1,2 , d1,3 , . . . , dj,j+2 , . . . , dn−2,n ], etc.
A la n−1-ième étape, on aboutit donc au tableau [d1,1 , d1,2 , d1,3 , . . . , , d1,n ].
On utilisera la syntaxe PNewton(X, Y ). Les calculs seront faits dans le tableau Y . [ S ]
4. Avec la forme du Newton, il est très facile d’ajouter un nouveau point A0 (x0 , y0 ).
Écrire une fonction newpoint passant du polynôme interpolateur P de (x1 , y1 ), . . . , (xn , yn )
(écrit sous sa forme de Newton) à celui des n + 1 points (x0 , y0 ), (x1 , y1 ), . . . , (xn , yn ).
Avec la syntaxe newpoint(X, P, x0 , y0 ), où X est la liste des n abscisses initiales, le résultat
sera le tableau de la forme de Newton du polynôme interpolant A0 , . . . , An . [ S ]
5. Écrire une fonction evalnewton calculant la valeur en un point x quelconque du polynôme
d’interpolation P des n points Ak (xk , yk ). La syntaxe sera evalnewton(X, P, x), où X est la
liste des n absicsses et où P est le tableau de taille n représentant la forme de Newton du
polynôme interpolateur. [ S ]
Cette application est un morphisme d’anneaux, injectif car son noyau est réduit à 0.
x mod n1 = a1
Il est donc bijectif pour des raisons de cardinal.
x mod n2 = a2
En particulier, pour tous entiers a1 , . . . , ar : ∃ ! x ∈ [ 0, . . . , n−1 ], (S)
..
.
Ce résultat est communément appelé théorème chinois. x mod nr = ar
1. Calcul des coefficients de Bezout.
(a) Écrire une fonction récursive bezout recevant les entiers positifs m, n et renvoyant dans un
tableau [u, v, u ∧ v] les coefficients u, v tels que um + vn = u ∧ v. Pour cela, et si m = nq + r
est la division de m par n, on notera comment passer d’un couple de coefficients de Bezout
de (n, r) à un couple de coefficients de Bezout de (m, n). [ S ]
(b) Dans cette question, on calcule la solution x, au moyen de deux schémas de Horner.
On pose b1 = a1 , puis b2 = (a2 − b1 )u1,2 mod n2 , etc, et finalement
br = [([(ar − b1 )u1,r − b2 ]u2,r − b3 ) · · · − br−1 ] ur−1,r mod nr
Pr k−1
Q
Montrer que la solution x du système (S) s’écrit x = bk ni .
k=1 i=1
Vérifier que x peut être calculé en utilisant un schéma de Horner.
En déduire une nouvelle version de la fonction chinese.
Remarque : Cette deuxième méthode a l’avantage de minimiser le nombre de “modulos”
à calculer, et de ne produire aucun calcul intermédiaire qui sortirait de [0, . . . , n−1]. [ S ]
système de numération “à base variable” vers la numération décimale (ou en base 10p si on veut p
chiffres à la fois.) Cette conversion s’effectue en utilisant des calculs “à la Horner”.
1. Une numération à base variable, adaptée au nombre e
On note B l’ensemble des suites d’entiers (bn )n≥1 telles que
– Pour tout n ≥ 2, bn ∈ {0, . . . , n − 1}, mais b1 est quelconque dans Z.
– Pour tout n ≥ 1, il existe m ≥ n tel que bm < n − 1.
∞
P bn
On va voir que tout x s’écrit d’une manière unique x = n! , où la suite (bn ) est dans B.
n=1
On pourra alors noter x = (b1 , b2 , . . . , bn , . . .)b .
On peut comparer ce développement avec la représentation décimale.
Notons en effet D l’ensemble des suites d’entiers (dn )n≥1 telles que
– Pour tout n ≥ 2, dn ∈ {0, . . . , 9}, mais d1 est quelconque dans Z.
– Pour tout n ≥ 1, il existe m ≥ n tel que dm < 9.
∞
P dn
On sait qu’on a une unique écriture x = 10n−1 , où la suite (dn )n≥1 est dans D.
n=1
Plus précisément, on a d1 = [x] et, pour tout n ≥ 2, dn = [10n−1 x] mod 10.
Ce qui distingue les deux types de numération, c’est que l’écriture décimale utilise la base
fixe d = 10 (et on décompose sur des puissances successives de 1/10n ) alors que l’écriture
x = (b1 , b2 , . . . , bn , . . .)b utilise une “base” variable 1, 2, 3, . . ., et une décomposition sur les 1/n!
∞
P 1
Evidemment pour e = exp(1), on a : e = 2 + k! c’est-à-dire e = (2, 1, 1, . . . , 1, . . .)b .
k=2
Un algorithme de conversion de la base variable b à la base 10 (ou mieux à une base 10p ),
permettra donc de récupérer les chiffres décimaux du nombre e.
P bk
(a) Soit (bn )n≥1 une suite de B. Montrer que k! converge. On note x sa somme.
n k≥1 ∞
P bk P bk
Pour tout n ≥ 0, on pose xn = k! (par convention, x 0 = 0) et r n = k! .
k=1 k=n+1
1
Montrer que pour tout n de N∗ , on a : 0 ≤ rn < n!
En déduire que b1 = [x] et, pour tout n ≥ 2, bn = [n!x] − n!xn−1 = [n!x] mod n. [ S ]
(a) Montrer qu’un développement régulier (0, p1 , p2 , p3 , . . .)P converge vers un réel de [0, 2[.
La partie entière de (p0 , p1 , p2 , p3 , . . .)P est donc égale à p0 ou à p0 + 1.
Montrer qu’il n’y a pas unicité de la représentation d’un réel x dans le système P. [ S ]
n−1
P
(b) Écrire une fonction todec2 calculant xn = pk uk à partir de X = [p0 , . . . , pn−1 ].
k=0
On utilisera la syntaxe todec2(X), sans vérifier si le tableau X est correct. [ S ]
(c) Soit xn = (p0 , p1 , p2 , . . . , pn−1 , 0, . . .)P la somme d’un développement régulier fini.
Soit m un entier strictement positif. Imaginer un algorithme permettant d’obtenir un
développement régulier de 10m xn . [ S ]
(d) Ecrire une fonction goutte2, comme celle de la question (2b), réalisant la conversion
étudiée à la question précédente. Vérifier qu’une application répétée de cette fonction
20
P
donne par exemple les 30 premières décimales de π21 = (2, 2, 2, . . . , 2)P = 2 uk . [ S ]
+∞ m−1 k=0
P P
(e) On sait que π = 2 uk . Pour tout m ≥ 1, on pose πm = 2 uk .
k=0 k=0
Vérifier que 0 < π − πm < 4um (observer que uk < 21 uk−1 pour tout k ≥ 1.)
Montrer en outre que um est strictement inférieur à 23 2−m , pour m ≥ 1.
En déduire que si m ≥ 10 −n
3 n, alors 0 < π − πm < 5 · 10 . [ S ]
(f) Déduire de ce qui précède une fonction chiffres pi donnant les n premières décimales
de π, avec la syntaxe chiffres pi(n, m), le paramètre m indiquant que les décimales sont
calculées par groupes de m chiffres consécutifs.
Le résultat sera donné sous la forme d’une chaı̂ne de caractères. [ S ]
Corrigé
I. Évaluation d’un polynôme
Deux versions de l’algorithme de Horner :
n
ak X k est représenté par le tableau P = [an , an−1 , . . . , a1 , a0 ].
P
1. Le polynôme P =
k=0
Le calcul de y = P (t) s’effectue en posant d’abord y = 0, puis successivement :
y ← yt + an = an , y ← yt + an−1 = an t + an−1 ,
y ← yt + an−2 = an t2 + an−1 t + an−2 , . . . , y ← yt + a0 = P (t)
Voici donc la fonction itérative evalh qui calcule y = P (t) :
> evalh:=proc(P::array(numeric),t::numeric)
> local y,k; y:=0; # initialisation
> for k to size (P) do y:=y*t+P[k] od; # boucle de calcul de y = P (t)
> RETURN(y) # renvoie la valeur calculée
> end:
On calcule ici la valeur du polynôme P = 3X 4 − 5X 2 + 2X + 1 au point t = 100 :
> P:=array([3,0,-5,2,1]): evalh(P,100);
299950201
Il est clair que l’algorithme précédent nécessite n additions et n multiplications. [ Q ]
n n−1
ak X k , et le quotient Q = ak+1 X k dans la division de P par X.
P P
2. Soit P =
k=0 k=0
Pour tout réel t, on a donc y = P (t) = tQ(t) + a0 .
P = [an , an−1 , . . . , a2 , a1 , a0 ]
Les polynômes P et Q sont représentés par les tableaux
Q = [an , an−1 , . . . , a2 , a1 ]
On voit que pour calculer y = P (t), il suffit de calculer z = Q(t) et de poser y = tz + a0 .
Pour évaluer Q(t), on peut encore utiliser le tableau initial P , à condition de se limiter aux
n + 1 premiers coefficients, c’est-à-dire à an , an−1 , . . . , a2 , a1 .
Il en découle la fonction evalhr, version récursive de l’algorithme de Horner.
Tout le travail est effectué par la fonction locale h, qui utilise toujours le tableau P représentant
le polynôme initial, mais qui reçoit en argument la longueur du sous-tableau de P représentant
l’un polynômes quotients successifs. Pour calculer y = P (t), il suffit donc d’un appel initial à
cette fonction locale, en lui transmettant la taille du tableau P .
> evalhr:=proc(P::array(numeric),t::numeric)
> local h;
> h:=proc(m)
> if m=1 then P[1] else h(m-1)*t+P[m] fi;
> end:
> RETURN(h(size(P))); # appel initial, sur tout la longueur de P
> end:
Ce sont les mêmes calculs que dans la question 1.a (algorithme de Horner itératif), mais il faut
conserver les résultats intermédiaires plutôt que de se contenter du résultat final.
1. Pour remplir le tableau Q, on écrira donc successivement :
Q[1] ← P [1], Q[2] ← Q[1] t+P [2], Q[3] ← Q[2] t+P [3], Q[n−1] ← Q[n−2] t+P [n−1]
On en déduit la forme itérative pour la fonction quo1 :
> quo1:=proc(P::array(numeric),t::numeric)
> local n,Q,k; n:=size (P); # taille du tableau P
3. La méthode est celle qui a été vue dans la question I-4 : On procède toujours par identification,
et une simple boucle permet de calculer successivement tous les coefficients bk .
On a d’abord : bn = an , bn−1 = an−1 − αbn , puis : ∀ k ∈ {1, . . . , n−2} : bk = ak − αbk+1 − βbk+2 .
Par identification des termes constants, on trouve enfin b0 = a0 − βb2 .
Comme bn , bn−1 , . . . , b0 doivent aller dans les cellules P [1], P [2], . . . , P [n+1] de P , on écrira :
P [2] ← P [2] − αP [1], puis ∀k ∈ {3, . . . , n}, P [k] ← P [k] − αP [k−1] − βP [k−2]
Puisque deg P ≤ n, on a deg Qk ≤ n−k pour tout k. En particulier Qn est une constante bn .
n
Inversement ces égalités donnent P = b0 +b1 (X −t)+b2 (X −t)2 + · · · + bn (X −t)n = bk (X −t)k .
P
k=0
On considère ici P = X 4 + 2X 3 − X 2 + 3X + 1.
(
P (X + 2) = X 4 + 10X 3 + 35X 2 + 55X + 35
On voit que
P (X) = (X −2)4 +10(X −2)3 +35(X −2)2 +55(X −2)+35
> P:=array([1,2,-1,3,1]): Translat(P,2); eval(P);
[1, 10, 35, 55, 35]
[Q]
2. Pour réécrire la procédure précédente, sous forme d’une fonction, il faut tout d’abord former
une copie Q indépendante du tableau initial P (avec l’instruction copy). Si ensuite on veut ne
plus utiliser la procédure Quo1, il suffit d’en recopier le contenu (à quelques détails près) dans
la fonction translat. Le résultat fait apparaı̂tre une double boucle finalement très simple.
> translat:=proc(P::array(numeric),t::numeric)
> local n,Q,j,k:
> n:=size (P); Q:=copy(P); # initialisations
> for k from n to 2 by -1 do # boucle de calcul du k-ième coefficient
> for j from 2 to k do # boucle de division par X −t
> Q[j]:=Q[j-1]*t+Q[j] # les calculs se font dans le tableau Q
> od;
> od;
> RETURN(eval(Q)); # renvoie le contenu du tableau Q
> end:
On reprend l’exemple qui a servi à illustrer la procédure précédente.
> P:=array([1,2,-1,3,1]): Q:=translat(P,2);
Q := [1, 10, 35, 55, 35]
[Q]
3. Pour former Q(x) = P (X + t), on peut procéder en trois étapes. On forme successivement
Q1 (X) = P (tX), puis Q2 (X) = Q1 (X + 1) = P (tX + t), puis Q(X) = Q2 (X/t) = P (X + t).
La translation se fait sans produit. Les deux autres étapes nécessitent n produits (ou divisions),
et il en faut à peu près autant pour créer le tableau contenant les puissances successives de t.
Voici la fonction (baptisée translat2), qui illustre cette idée. On remarquera le test initial
(sans lequel la fonction provoquerait une erreur dans la cas t = 0.)
> translat2:=proc(P::array(numeric),t::numeric)
> local n,Q,T,j,k:
> if t=0 then RETURN(eval(P)) fi; # ne change rien si t = 0
> n:=size(P); Q:=copy(P); T:=array(1..n); T[n]:=1; # initialisations
> for k from n-1 to 1 by -1 do # passe de X à tX
> T[k]:=t*T[k+1]; Q[k]:=Q[k]*T[k]
> od;
> for k from n to 1 by -1 do # passe de X à X + 1
> for j from 2 to k do Q[j]:=Q[j-1]+Q[j] od;
> Q[k]:=Q[k]/T[k]; # puis de X à X/t
> od;
> RETURN(eval(Q)); # renvoie Q(X) = P (X + t)
> end:
On reprend l’exemple utilisé précédemment.
> P:=array([1,2,-1,3,1]): Q:=translat2(P,2);
Q := [1, 10, 35, 55, 35]
[Q]
n
P (k) (t)
(X −t)k (formule de Taylor en t.)
P
4. On sait que P = k!
k=0 n
bk (X −t)k .
P
La question précédente a permis de calculer les bk tels que P =
k=0
On a bien entendu P (k) (t) = k! bk pour tout k de {0, 1, . . . , n}.
On appelle donc translat puis on transforme [bn , . . . , b1 , b0 ] en [n! bn , . . . , 1! b1 , 0! b0 ].
Pour rester “basique” on n’utilise pas la factorielle, mais un accumulateur local f .
> derivs:=proc(P::array(numeric),t::numeric)
> local n,Q,k,f:
> n:=size (P); f:=1; # degP = n−1, et 1 ! = 1
> Q:=translat (P,t); # calcule Q(x) = P (x+t)
> for k from 2 to n-1 do
> f:=f*k; # place k! dans la variable f
> Q[n-k]:=f*Q[n-k]: # calcule la dérivée k-ième de P en t
> od;
> RETURN(eval(Q)); # renvoie le tableau des dérivées successives
> end:
On considère à nouveau le polynôme P = X 4 + 2X 3 − X 2 + 3X + 1.
On voit que [p(4) (2), p(3) (2), p00 (2), p0 (2), p(2)] = [24, 60, 70, 55, 35].
> P:=array([1,2,-1,3,1]): Q:=derivs(P,1);
Q := [24, 60, 70, 55, 35]
[Q]
2. Pour tout a de R, le nombre de racines réelles de P qui sont strictement supérieures à a est
égal au nombre de racines strictement positives de Q(X) = P (X + a).
Il suffit donc d’appeler la fonction varsign sur le tableau Q, lui même obtenu à partir du
tableau P grâce à la fonction translat.
> rootsup:=proc(P::array(numeric),a::numeric)
> RETURN(varsign (translat (P,a))) # sans commentaire...
> end:
Voici un polynôme dont les racines réelles sont 1, 3, 5 avec les multiplicités 1, 2, 1.
> P:=sort(expand((x-1)*(x-3)^2*(x-5)*(x^2+1)));
P := x6 − 12x5 + 51x4 − 96x3 + 95x2 − 84x + 45
On forme le tableau P associé à ce polynôme. On obtient ensuite un majorant s du nombre de
racines dans ]a, +∞[, avec successivement :
– a = 0 : on trouve s = 6 (il y a 4 racines > 0.) Il est normal que la différence soit paire.
– a = 1 : on trouve s = 3, ce qui confirme qu’il y a une ou trois racines > 1 (il y en a en fait
trois). On remarque que la racine égale à 1 n’est plus comptée.
– a = 4 : on trouve s = 1, ce qui prouve qu’il y a une racine > 4.
– a = 6 : on trouve s = 0 et c’est normal.
> P:=array([1,-12,51,-96,95,-84,45])
> rootsup(P,0),rootsup(P,1),rootsup(P,4),rootsup(P,6);
6, 3, 1, 0
[Q]
3. Le polynôme P possède autant de racines strictement inférieures à a que le polynôme Q(X) =
P (−X) en possède qui sont strictement supérieures à −a.
Il suffit donc de transformer le polynôme P en le polynôme Q (ou en −Q, peu importe) en
changeant un signe sur deux, puis d’appeler rootsup avec les arguments Q et −a.
> rootinf:=proc(P::array(numeric),a::numeric)
Le polynôme d’interpolation associé aux points A1 (x1 , y1 ), A2 (x2 , y2 ), A3 (x3 , y3 ) est donc :
y3 − y2 y2 − y1
−
y2 − y1 x − x2 x2 − x1
P = y1 + (X − x1 ) + 3 (X − x1 )(X − x2 )
x2 − x1 x3 − x1
On constate effectivement que deg P ≤ 2 et que :
y2 − y1
P (x1 ) = y1 et P (x2 ) = y1 + (x2 − x1 ) = y2
x2 − x1
y3 − y2 y2 − y1
−
y2 − y1 x − x2 x2 − x1
P (x3 ) = y1 + (x3 − x1 ) + 3 (x3 − x1 )(x3 − x2 )
x2 − x1 x3 − x1
y2 − y1 y −y
3 2 y2 − y1
= y1 + (x3 − x1 ) + − (x3 − x2 )
x2 − x1 x3 − x2 x2 − x1
y2 − y1
= y1 + ((x3 − x1 ) − (x3 − x2 )) + y3 − y2 = y3
x2 − x1
Voici maintenant un autre exemple d’utilisation de la fonction pnewton :
> X:=array([-1,0,1,2,3]): Y:=array([1,2,-3,-2,-7]): pnewton(X,Y);
[1, 1, −3, 2, −1]
Ce résultat signifie que le polynôme P de R4 [X] qui vérifie :
P (−1) = 1, P (0) = 2, P (1) = −3, P (2) = −2, P (3) = −7,
est donné par
P = 1 + (X +1) − 3(X +1)X + 2(X +1)X(X −1) − (X +1)X(X −1)(X −2)
[Q]
3. L’idée est de mener les calculs comme indiqué dans le tableau ci-dessous (avec n = 4).
Chaque colonne représente une étape de l’algorithme, et à chaque étape un coefficient nouvel-
lement calculé prend la place d’un coefficient calculé à l’étape précédente.
La première colonne représente bien sûr le vecteur Y initial.
On voit assez bien que les calculs doivent être menés dans une double boucle. L’indice de boucle
externe indique à quelle étape (dans quelle colonne) on se trouve, et l’indice de la boucle interne
parcourt la partie utile de cette colonne (selon les indices décroissants, pour qu’un coefficient
ne soit pas “recourvert” alors qu’il est encore utile.)
d1,1 = y1
d2,2 − d1,1
d2,2 = y2 d1,2 =
x2 − x1
d3,3 − d2,2 d2,3 − d1,2
d3,3 = y3 d2,3 = d1,3 =
x3 − x2 x3 − x1
d4,4 − d3,3 d3,4 − d2,3 d2,4 − d1,3
d4,4 = y4 d3,4 = d2,4 = d1,4 =
x4 − x3 x4 − x2 x4 − x1
5. Considérons par exemple les quatre points A1 (x1 , y1 ), . . . , A4 (x4 , y4 ), dans cet ordre.
Leur polynôme interpolateur sous sa forme de Newton est représenté par [d1,1 , d1,2 , d1,3 , d1,4 ].
Ainsi : P = d1,1 + d1,2 (X − x1 ) + d1,3 (X − x1 )(X − x2 ) + d1,4 (X − x1 )(X − x2 )(X − x3 ).
On peut réécrire le polynôme P sous la forme suivante (schéma de Horner) :
P = d1,1 + (X − x1 ) (d1,2 + (X − x2 ) (d1,3 + (X − x3 )d1,4 ))
Ainsi pour évaluer y = P (x), on pourra poser y = 0 puis effectuer successivement :
y ← d1,4 + (x − x4 )y = d1,4 y ← d1,3 + (x − x3 )y = d1,3 + (x − x3 )d1,4
y ← d1,2 + (x − x2 )y = d1,2 + (x − x2 ) (d1,3 + (x − x3 )d1,4 )
y ← d1,1 + (x − x1 )y = d1,1 + (x − x1 ) (d1,2 + (x − x2 ) (d1,3 + (x − x3 )d1,4 ))
La fonction evalnewton s’en déduit très simplement :
> evalnewton:=proc(X,P,x)
> local y,k; y:=0;
> for k from size(P) to 1 by -1 do y:=P[k]+(x-X[k])*y od;
> RETURN(y)
> end:
On reprend ici l’exemple des cinq points (−1, 1), (0, 2), (1, −3), (2, −2), (3, −7).
La procédure PNewton place la forme de Newton du polynôme interpolateur dans Y .
On évalue ensuite ce polynôme en x, ce qui illustre le mode d’évaluation.
Enfin, on vérifie que ce polynôme prend les valeurs 1, 2, −3, −2, −7 en −1, 0, 1, 2, 3.
> X:=array([-1,0,1,2,3]): Y:=array([1,2,-3,-2,-7]):
> PNewton(X,Y); eval(Y), P:=evalnewton(X,Y,x);
> seq(evalnewton(X,Y,X[k]),k=1..size(X));
[1, 1, −3, 2, −1], P := 1 + (x + 1)(1 + x(−3 + (x − 1)(4 − x)))
1, 2, −3, −2, −7
[Q]
(b) On commence par les égalités (Em ) (triplet [1, 0, m]) et (En ) (triplet [0, 1, m]).
On procède à des divisions successives sur les seconds membres, jusqu’à un reste nul.
A chaque pas, on trouve un nouveau triplet [u, v, δ], où δ est l’un des restes successifs.
A la fin, on aboutit à [u, v, m ∧ n]. NB : la solution récursive était plus simple !
> bezout2:=proc(m::integer,n::integer)
> local m,n,C1,C2,q,r,T,k:
> a:=m; b:=n; # recopie les deux entiers initiaux
> C1:=array([1,0,m]); # relation de Bezout 1.m + 0.n = m
> C2:=array([0,1,n]); # relation de Bezout 0.m + 1.n = n
> while b<>0 do # tant que le dernier reste est non nul
> q:=floor(a/b); r:=a-q*b; # division de a par b
> a:=b; b:=r; # actualise les valeurs de a et de b
> T:=copy(C1); C1:=copy(C2); # C1 = [u, v, a] tel que um + vn = a
> for k to 3 do
> C2[k]:=T[k]-q*C1[k]; # C2 = [u0 , v 0 , b] tel que u0 m + v 0 n = b
> od;
> od;
> RETURN(eval(C1)); # C1 = [u, v, m ∧ n], avec um + vn = m ∧ n
> end:
On reprend l’exemple utilisé précédemment.
> bezout2(14938,9471);
[26, −41, 77]
[Q]
2. Solution d’un système de congruences
(a) Pour tous indices i 6= j, les égalités ui,j ni + uj,i nj = 1 impliquent ui,j ni ≡ 1 (nj ).
≡ 0 (ni ) si i 6= j
Q
Ainsi Mj = ui,j ni
i6=j ≡ 1 (nj )
Pr
Il en découle qu’on a effectivement x = aj Mj ≡ ai (ni ), pour tout i de {1, . . . , r}.
j=1
> chinese:=proc(A::array(integer),N::array(integer))
> local r,U,n,i,j,B,M,x;
> r:=size (N); # nombre de congruences
> U:=array(1..r,1..r); # prépare le tableau des u[i, j]
> n:=1; for i to r do n:=n*N[i] od; # calcule le produit n des n[k]
> for i to r do for j to i-1 do # pour 1 ≤ j < i ≤ r,
> B:=bezout (N[i],N[j]); # résout u[i, j]n[i] + u[j, i]n[j] = 1
> if B[3]<>1 then ERROR("gcd<>1") fi; # erreur si n[i] ∧ n[j] 6= 1
> U[i,j]:=B[1]; U[j,i]:=B[2]; # valeurs de u[i, j] et u[j, i]
> od; od;
> M:=array(1..r); # prépare le tableau des M [j]
> for j to r do M[j]:=1; # boucle de calcul du tableau M
> for i to r do # boucle pour calculer M [j]
> if i<>j then # × par U [i, j]M [i] si j 6= i
> M[j]:=(M[j]*U[i,j]*N[i]) mod n
> fi;
> od; od;
> x:=0; for j to r do # boucle de calcul de la solution x
> x:=(x+A[j]*M[j]) mod n;
> od;
> RETURN(x); # renvoie la solution x du système
> end:
Sur cet exemple, on met en place le système de congruences
x ≡ 11 (143) x ≡ 35 (223) x ≡ 42 (199) x ≡ 17 (301) x ≡ 22 (211)
La solution obtenue est x = 74269611713.
On constate que x est bien dans l’intervalle [0, . . . , n−1], avec ici n = 403035153521.
> A:=array([11,35,42,17,22]):
> N:=array([143,223,199,301,211]):
> n:=mul(N[k],k=1..5);
> chinese(A,N);
n := 403035153521
x := 74269611713
On vérifie que la solution obtenue est correcte :
> seq(x mod N[k],k=1..5);
11, 35, 42, 17, 22
Remarque : dans le listing ci-dessus (cf les lignes M[j] :=... et x :=...) on a effectué les
calculs intermédiaires “modulo n”. Sans cela, ces calculs conduisent à des entiers beaucoup
plus grands que n, et qui pourraient excéder les capacités arithmétiques du système (pas
celles de Maple, évidemment.) [ Q ]
j−1
Q j−1
P j−1
Q
(b) Après développement, on constate que bj = aj ui,j − (bk ui,j ) mod nj .
i=1 k=1 i=k
D’autre part, les égalités ui,j ni + uj,i nj = 1 donnent ui,j ni ≡ mod nj .
j−1
Q j−1
P k−1
Q
On en déduit bj n i = aj − (bk ni ) mod nj .
i=1 k=1 i=1
k−1
Q
Posons alors ck = bk ni .
i=1
j−1
P
Ce qui précède montre que cj ≡ aj − ck mod nj .
k=1
j
P
Ainsi ck ≡ ai mod ni .
k=1
r
P r
P k−1
Q
Conclusion : l’entier x solution du système (S) s’écrit x = ck = (bk ni ).
k=1 k=1 i=1
Enfin, l’entier x peut être calculé au moyen du schéma de Horner suivant :
x = b1 + (b2 + · · · + (br−2 + (br−1 + br nr−1 )nr−2 ) · · · n2 )n1
On peut maintenant écrire la nouvelle version de la fonction chinese.
Elle est beaucoup plus simple et efficace que la précédente.
On note en particulier qu’il n’est plus nécessaire d’utiliser de variable locale n pour y
placer le produit des nk , ni bien sur la tableau local M utilisé dans la première version.
La principale qualité de cette deuxième méthode est que tous les calculs intermédiaires se
font dans [0, . . . , n−1]. Les seuls calculs de congruences se font modulo les nk (et non plus
modulo n comme dans la première version).
C’est en particulier frappant dans le calcul final de la solution x, qui ne fait pas intervenir
aucune congruence...
> chinese:=proc(A::array(integer),N::array(integer))
> local r,U,i,j,B,x;
> r:=size(N);
> U:=array(1..r,1..r); # formation du tableau des u[i, j]
> for i to r do for j to i-1 do
> B:=bezout(N[i],N[j]);
> if B[3]<>1 then ERROR("pgcd<>1") fi;
> U[i,j]:=B[1];
> U[j,i]:=B[2];
> od; od;
> B:=copy(A); # formation de la suite des b[i]
> for i to r do
L’inégalité stricte est justifiée par le fait qu’il existe k > n tel que bk < k − 1.
Les relations x = b1 + r1 et 0 ≤ r1 < 1 donnent alors b1 = [x].
Pour n ≥ 2, on peut écrire x = xn−1 + bn!n + rn , donc n!x = n!xn−1 + bn + n!rn .
n−1
P bk
Il est clair que n!xn−1 = n (n−1)! k! est un entier divisible par n.
k=1
Puisque 0 ≤ n!rn < 1, on en déduit [n!x] = n!xn−1 + bn .
On trouve donc finalement bn = [n!x] mod n, pour tout n ≥ 2. [ Q ]
(b) Supposons que le réel x s’écrive sous la forme indiquée.
D’après ce qui précède, on a nécessairement b1 = [x] et, ∀ n ≥ 2, bn = [n!x] mod n.
Il est d’abord évident que b1 est dans Z et que, pour tout n ≥ 2, bn est dans {0, . . . , n − 1}.
n ∞
P bk P bk
En reprenant les notations de l’énoncé, posons xn = k! et r n = k! .
k=1 k=n+1
Pour tout n ≥ 2, posons αn = [n!x] et soit αn = nqn + bn la division de αn par n.
Pour tout n ≥ 2, on a successivement :
1
Pour tout n ≥ 1, on a n! x − 1 < [n! x] ≤ n! x donc x − n! < xn ≤ x.
1
Ainsi xn est-il une valeur approchée de x, par défaut, à n! près.
∞
P bn
On a obtenu lim xn = x, ce qui prouve que x = n! .
n→∞ n=1
Il reste à prouver qu’on n’a jamais bn = n − 1 à partir d’un certain rang.
Supposons au contraire que bn = n − 1 pour tout n > p.
∞ ∞ ∞ p
P bn P n−1 P 1 1 1 P bn 1
Alors rp = n! = n! = (n−1)! − n! = p! , donc x = n! + p! .
n=p+1 n=p+1 n=p+1 n=1
On en déduit que p! x est un entier, et donc que (p+1)!x est un entier multiple de p+1.
Ainsi bp+1 = [(p+1)!x] mod (p+1) = (p+1)!x mod (p+1) = 0 : contradiction ! [ Q ]
n
P bk
(c) Pour calculer xn = k! à partir de B = [b1 , . . . , bn ], on utilise un schéma de Horner.
k=1
On peut en effet écrire :
b 1 1 1 1 1
n
xn = ··· + bn−1 + bn−2 + bn−3 + ··· + b2 + b1
n n−1 n−2 n−3 3 2
Le réel xn peut donc être calculé en l’initialisant à la valeur 0 et en éxécutant les instruc-
xn
tions xn ← k+1 + B[k], de k = n à k = 1 (avec un “pas” de −1.)
Voici donc la fonction todec :
> todec:=proc(B::array(integer),n::integer)
> local x,k: x:=0;
> for k from n to 1 by -1 do x:=x/(k+1)+B[k]; od;
> RETURN(x);
> end:
A titre d’exemple, on forme le tableau des 16 premiers chiffres de la représentation de e :
> B:=array([2,1$15]);
B := [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
(d) Voici tovar. On remplit le tableau des bk , avec b1 = [x] et bk = [k!x] mod k si k ≥ 2.
On calcule k!x par accumulation progressive dans une variable locale y.
> tovar:=proc(x::numeric,n::integer)
> local B,y,k:
> B:=array(1..n); B[1]:=floor(x); y:=x;
> for k from 2 to n do
> y:=y*k; B[k]:=floor(y) mod k;
> end;
> RETURN(eval(B));
> end:
Sur cet exemple, on forme la décomposition de e (ou plus exactement de l’approximation
de e sur 10 chiffres significatifs : il n’est donc pas étonnant que les coefficients diffèrent de
1 au bout d’un certain temps.)
> e:=evalf(exp(1)); tovar(e,15);
e := 2.718281828
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 10]
[Q]
e10 := 2.7182818011463844797178130511463844797178
Dans les calculs suivants, on a recours à la variable Y pour former des copies du tableau
X initial (rappelons que la procédure goutte modifie le tableau qui lui est transmis.)
Sur ce premier exemple, on convertit 10 e10 dans la base B.
Dans le tableau obtenu, la première composante est la partie entière de 10 e10 .
> Y:=copy(X): goutte(Y,1); eval(Y);
[27, 0, 1, 0, 1, 5, 4, 3, 2, 0]
On convertit maintenant 1010 e10 . On voit apparaı̂tre les 10 premières décimales de e10 .
> Y:=copy(X): goutte(Y,10); eval(Y);
[27182818011, 0, 2, 3, 0, 3, 6, 6, 2, 0]
On convertit ici 1040 e10 , et on retrouve les 40 premières décimales de e10 . Si ce calcul est
possible en une fois, c’est évidemment grâce aux possibilités arithmétiques de Maple.
> Y:=copy(X): goutte(Y,40); eval(Y);
[27182818011463844797178130511463844797178, 0, 0, 3, 0, 3, 6, 6, 2, 0]
On peut en fait obtenir le même résultat, mais par étapes (notamment si on travaille
sur un système qui ne supporte qu’une arithmétique limitée des entiers.) Dans le calcul
ci-dessous, et à quatre reprises, on annule le premier coefficient de Y (ce qui revient à
s’assurer que le réel y figurant dans ce tableau est compris entre 0 et 1) puis on convertit
1010 y dans la base B (cette valeur remplace la valeur précédente de y).
Chaque étape fournit, dans Y [1], 10 décimales supplémentaires du nombre e10 .
> Y:=copy(X): for k to 4 do Y[1]:=0; goutte(Y,10); print(Y); od:
[7182818011, 0, 2, 3, 0, 3, 6, 6, 2, 0]
[4638447971, 1, 1, 2, 3, 4, 3, 6, 2, 0]
[7813051146, 0, 2, 1, 1, 0, 5, 6, 2, 0]
[3844797178, 0, 0, 3, 0, 3, 6, 6, 2, 0]
On voit que ce calcul pourrait être poursuivi indéfiniment. On obtiendrait ainsi autant de
décimales qu’on le souhaite pour le nombre e10 . Evidemment, et si c’est le nombre e qui
nous intéresse, seules sont dignes d’intérêt les décimales communes de e et de e10 .
1
Or 0 < e − e10 < 10! < 3e-7. Donc e et e10 ont a priori six décimales communes.
En fait e ≈ 2.71828182846 et e10 ≈ 2.71828180114 (sept décimales communes.) [ Q ]
vn+1
(c) Pour tout n ≥ 1, posons vn = n!10−(n+1) . On a = n+1
10 .
vn
La suite (vn ) est donc croissante à partir de n = 9. D’autre part v27 ≈ 1.09 > 1.
1
Pour ≥ 27, on a donc n! < 10−(n+1) . On en déduit 0 < e − en < 10−(n+1) .
Les nombres e et en ont donc les mêmes n premières décimales, sauf erreur d’arrondi
finale. Voici la fonction chiffres e, qui donne n décimales du nombres e, obtenues par
tranches de m décimales successives.
> chiffres_e:=proc(n::integer,m::integer)
> local X,s,t;
> s:="2,"; # initialise la chaı̂ne de caractères
> X:=vector(max(n,27),1); # vecteur de taille n, coefficients=1
> to ceil(n/m) do # au moins n/m fois de suite
> X[1]:=0; # annule la partie entière
> goutte(X,m); # multiplie par 10ˆm et convertit
> t:=convert(10^m+X[1],string); # extrait la partie entière
> s:=cat(s,substring(t,2..m+1)); # ajoute les m nouveaux chiffres
> od;
> RETURN(substring(s,1..n+2)) # renvoie la chaı̂ne, avec n décimales
> end:
Maple nous donne ici le nombre e avec 54 chiffres significatifs (donc 53 décimales.)
La fonction chiffres e nous donne ensuite le même résultat.
Les décimales sont ici obtenues par tranches de 5, mais ça n’influe pas sur le résultat final.
> convert(evalf(exp(1),54),string);
> chiffres_e(53,5);
”2.71828182845904523536028747135266249775724709369995957”
”2, 71828182845904523536028747135266249775724709369995957”
Si on compare avec le résultat précédent, on voit que notre fonction chiffres e donne
49 décimales exactes, alors que l’arrondi obtenu par la fonction intégrée de Maple produit
une erreur sur les quatre dernières de ces 49 décimales.
> convert(evalf(exp(1),50),string);
> chiffres_e(49,5);
”2.7182818284590452353602874713526624977572470937000”
”2, 7182818284590452353602874713526624977572470936999”
[Q]
3. Le calcul des décimales du nombre π
(a) On rappelle que uk = 3 · 51··72···
· 3 ··· · k
· (2k+1) pour tout k ≥ 1, et u0 = 1.
On se donne une suite (pk )k≥1 , avec 0 ≤ pk ≤ 2k pour tout k ≥ 1.
On rappelle l’hypothèse selon laquelle, pour tout n ≥ 1, il existe n0 ≥ n tel que pn0 < 2n0 .
k
Pour tout k ≥ 1, on a uk = 2k+1 uk−1 donc kuk = kuk−1 − (k + 1)uk .
Pour tous entiers 1 ≤ n ≤ m, on peut alors écrire :
m
P m
P Pm
0≤ pk uk ≤ 2 kuk = 2 (kuk−1 − (k+1)uk ) = 2(nun−1 − (m+1)um )
k=n k=n k=n
La division s’est donc traduite par une retenue (n−1)qn−1 , reportée sur 10m pn−2 .
– On divise maintenant p0n−2 = 10m pn−2 + (n−1)qn−1 par 2n−3.
Cette division s’écrit p0n−2 = qn−2 (2n−3) + rn−2 , avec 0 ≤ rn−2 ≤ 2(n−2) :
n−4
10m xn = 10m pk uk + (10m pn−3 + (n−2)qn−2 )un−3 + rn−2 un−2 + rn−1 un−1
P
k=0
π21 = 3, 1415922987403396327019224 . . . ou
On sait maintenant que
π21 = 3, 1415922987403396327019225 . . .
Voici une nouvelle étape :
> X[1]:=0: goutte2(X,5); eval(X);
[96023, 1, 3, 6, 2, 8, 0, 9, 1, 18, 14, 2, 18, 26, 2, 14, 25, 9, 2, 2, 2]
π21 = 3, 141592298740339632701922496023 . . . ou
On sait donc que
π21 = 3, 141592298740339632701922496024 . . .
L’étape suivante permettrait évidemment de lever le doute sur la dernière décimale. [ Q ]
k
(e) Pour tout k ≥ 1, l’égalité uk = 2k+1 uk−1 donne effectivement uk < 12 uk−1 .
k−m
On en déduit, pour tout m ≥ 1 et tout k ≥ m : uk ≤ 12 um .
+∞
P +∞
P 1 k−m
Il en découle 0 < π − πm = 2 uk < 2um 2 = 4um .
k=m k=m
”3.1415926535897932384626433832795028841971693993751058209749445
9230781640628620899862803482534211706798214808651328230664
7093844609550582231725359408128481117450284102701938521105
5596446229489549303819644288109756659334461284756482337867
8316527120190914564856692346034861045432664821339360726024
9141273724587006606315588174881520920962829254091715364367
8925903600113305305488204665213841469519415116094330572703
6575959195309218611738193261179310511854807446237996274956
735188575272489122793818301194913”
On calcule maintenant ces décimales avec notre fonction chiffres pi.
> chiffres_pi(500,5);
”3, 1415926535897932384626433832795028841971693993751058209749445
9230781640628620899862803482534211706798214808651328230664
7093844609550582231725359408128481117450284102701938521105
5596446229489549303819644288109756659334461284756482337867
8316527120190914564856692346034861045432664821339360726024
9141273724587006606315588174881520920962829254091715364367
8925903600113305305488204665213841469519415116094330572703
6575959195309218611738193261179310511854807446237996274956
735188575272489122793818301194912”
[Q]