Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

Une cascade de décimales de $\pi$ : possible ou uto$\pi$que ?
Une narration de recherche é$\pi$que et mouvementée !
Article mis en ligne le 17 janvier 2025
dernière modification le 22 janvier 2025

par Angelo Laplace

C’est en relisant une dernière fois l’article « Des décimales en cascade » avant de le publier que Julien Baldacci a mentionné que l’on pouvait également calculer $\pi$ avec un algorithme de streaming ou algorithme compte-gouttes. Et ceci avec une belle efficacité ! Il est vrai que dans l’article d’origine, on s’était en fait attaqué à des nombres plutôt simples (nombre d’argent, nombre d’or, radicaux comme $\sqrt{3}$)... Avec succès. Et au comité de rédaction de la revue, nous étions déjà particulièrement ravis par la méthode que Julien nous avait apportée sur un plateau.
Mais $\pi$, évidemment, cela paraîtrait encore plus fort ! L’information nous semblait fiable, car nous pensions en avoir vu une mention dans le livre de Jean-Paul Delahaye, le fascinant nombre $\pi$. Alors Gérard Kuntz m’a demandé d’étudier la question. Le défi était osé. Mais difficile de refuser quelque chose à notre gentil rédacteur en chef, d’autant que cela promettait quelques rebondissements plutôt stimulants, sachant que "chasser" $\pi$ pour un amateur de mathématiques, c’est un peu comme la quête du Graal : un objectif plus ou moins incertain et qui s’apparente à un sacré jeu de $\pi$stes.
C’est cette recherche que je vous raconte, la manière dont je l’ai menée, avec souvent une infinie prudence, en entrant sur la pointe des $\pi$eds dans un domaine loin d’être familier et avec quelques déboires.
Un peu comme dans un (mauvais) roman d’aventures !


La recherche d’une méthode

Il existe beaucoup de programmes tout prêts sur internet pour calculer des décimales de $\pi$ mais ils n’ont pas grand chose à voir avec la méthode que Julien nous a présentée. Or, le postulat de base était qu’il fallait maintenir une certaine continuité avec l’article précédent. Et donc de laisser de côté les mastodontes que sont la formule de Machin, les formules de Ramanujan (dont je vous conseille le "portrait" dressé par Bernard Ycart ici->https://www.hist-math.fr/recits/ramanujan.html] ou la formule BBP (Bailey, Borwein et Plouffe).

Formule de Machin

Les méthodes que nous avions utilisées pour trouver les décimales des radicaux dans le premier article sont basées sur le développement en fractions continues des nombres ciblés. A cette occasion, nous avions parlé du théorème de Lagrange qui assure qu’être un nombre irrationnel quadratique est équivalent à avoir un développement en fraction continue périodique à partir d’un certain rang. Et c’est précisément cette périodicité qui nous permettait de produire des algorithmes compétents qui composent en boucle par les mêmes fonctions homographiques en nombre restreint.
Or, chacun le sait, $\pi$ est transcendant, c’est-à-dire non algébrique et a fortiori non quadratique. Il est donc illusoire d’espérer utiliser un développement en fraction continue qui soit périodique pour $\pi$. Difficile alors de composer par des fonctions homographiques dont on sait à l’avance qu’elles "apparaîtront comme ayant été aléatoirement choisies".
Evidemment, elles ne le sont pas : $\pi$ a bien un développement en fraction continue dont le début est [3, 7, 15, 1, 292, 1, 1, 1, 2, . . . ]. Mais aucune périodicité n’est à attendre donc.
Il existe certes un procédé de calcul des éléments de ce développement (que l’on pourrait confier à Python) mais celui-ci utilise de façon systématique des calculs d’inverses de nombres décimaux souvent très petits et va donc provoquer des difficultés de gestion d’arrondis et de flottants. D’autre part, pour les calculer, il faut connaître les décimales de $\pi$. C’est le serpent qui se mord la queue !
Néanmoins, en cherchant bien, $\pi$ offre quelques belles surprises avec les fractions continues :

Formule de Brouncker

La formule de lord Brouncker est la première représentation de $\pi$ de l’histoire en fraction continue autrement dit il s’agit d’une "quadrature infinie". Une conception qui déstabilisa ses pairs.

La formule suivante est aussi remarquable :

En changeant de base, on obtiendrait donc cette splendide écriture, pleine de régularité qui rappelle le développement en fraction continue de $\sqrt{10}$ : [3,$\overline{6}$].
Les "6" à l’infini sont prometteurs mais c’est le changement permanent de base qui rend possible ce que nous avions annoncé comme impossible, à savoir trouver une périodicité. De ce fait, la formule est tout aussi inutilisable car les fonctions homographiques de composition à droite auraient des numérateurs changeants, certes simples à programmer puisqu’il s’agit des carrés successifs des nombres impairs, mais n’assurant plus une autre propriété essentielle à notre propos du premier article : la stabilité de l’intervalle [0 ; 1] par les diverses fonctions homographiques de composition. Nous l’avons vu dans l’étude du nombre d’argent, c’est un critère fondamental pour assurer une convergence (rapide).

C’est finalement quand chatGPT m’a donné plusieurs développements en fractions continues erronés de $\pi$, que j’ai définitivement tourné le dos à cette piste.
Et je suis allé traîner sur le site de référence du nombre $\pi$ en France, à savoir le site du chercheur Boris Gourévitch pi314.net. Il n’est plus très souvent mis à jour, mais il possède une page sur les algorithmes compte-gouttes.

J’y ai trouvé la clé qui est d’écrire une série découverte par Euler sous la forme de Horner (celle qui permet de réduire le nombre de multiplications à effectuer dans un calcul polynomial) :

$\pi = 2 \sum_{n=0}^{\infty} \frac{2^n (n !)^2}{(2n+1) !} = 2 \sum_{n=0}^{\infty} \frac{1.2.3...n}{1.3.5...(2n+1)} = \Bigg( 2 +\frac{1}{3} \Big( 2 +\frac{2}{5} \Big( 2 +\frac{3}{7} \Big( 2 +\frac{4}{9} \Big( 2 +\frac{5}{11} \big( 2 +\frac{6}{13} ( ... ) \big) \Big) \Big) \Big) \Big) \Bigg) $

Alors qu’en base 10, $\pi$ s’écrit :

$\pi = \Bigg( \underline{3} + \frac{1}{10} \Big( \underline{1} + \frac{1}{10} \Big( \underline{4} + \frac{1}{10} \Big( \underline{1} + \frac{1}{10} \big( \underline{5} + \frac{1}{10} ( ... ) \big) \Big) \Big) \Big) \Bigg) $

On voit alors que si l’on considère une base à pas variable [1,$\frac{1}{3},\frac{2}{5},\frac{3}{7},\frac{4}{9},..$], dans cette base, l’expression de $\pi$ est [2, $\overline{2}$]. Autrement dit, dans cette base, $\pi$ est donc un des nombres les plus simples qui existent !
On connaît ainsi ses digits (le mot décimale est réservé au système décimal) dans cette base, et techniquement parlant pour obtenir les décimales de $\pi$ en base 10, une par une, il suffit de construire un algorithme qui opère un changement de base, c’est justement tout le principe de l’algorithme compte-gouttes.


La compréhension de la technique

On trouve alors toujours sur cette page, un tableau qui met en pratique la recherche des 3 premiers chiffres derrière la virgule.

On place à chaque étape les numérateurs et dénominateurs des pas de la base à pas variable sur les deux premières lignes du tableau. A la troisième ligne, on met l’expression de $\pi$ dans cette base, autrement dit les digits. On calcule leur produit par 10 sur la ligne suivante puisqu’on souhaite convertir en base 10. On initialise enfin la dernière colonne de la ligne retenue par un 0. Tout est prêt pour les calculs qui, attention, commencent par la colonne à droite et remplissent petit à petit les colonnes vers la gauche.

a r 1 2 3 4 5 6 7 8 9 10 11 12
b 3 5 7 9 11 13 15 17 19 21 23 25
digit dans la base 2 2 2 2 2 2 2 2 2 2 2 2 2
Produit par 10 20 20 20 20 20 20 20 20 20 20 20 20 20
retenue 0
Somme
Reste

Formellement, le principe général consiste à multiplier le digit par 10 et à en évaluer le reste après un équivalent de division euclidienne par le pas de la base à pas variable. Une retenue va apparaître à chaque calcul et provient du même phénomène qui fait que lorsque l’on multiplie 53 par 8, on multiplie d’abord 3 par 8, on retient 2 et on l’ajoute à la multiplication par 8 de 5 c’est à dire à la multiplication du digit suivant.

La ligne « produit par 10 » étant remplie, on calcule :

  • la somme de ce produit et du nombre « retenue », ici 20 + 0 =20. A placer dans la dernière colonne de la ligne « somme ».
  • la division euclidienne de ce résultat par le nombre de la ligne « b » correspondant à cette colonne soit ici :
    20 = 0 $\times$ 25 + 25. On place le reste 25 dans le tableau sur la ligne prévue.
  • le produit du quotient obtenu par le nombre « a » correspondant, ici 0 $\times$ 12 =0. On place le résultat dans la ligne « retenue » de la colonne suivante vers la gauche.

Comme le quotient était 0. Ce n’est pas très spectaculaire. On poursuit pour la colonne suivant en répétant les mêmes étapes.
20 + 0 = 20
20 = 0 $\times$ 23 + 20
0 $\times$ 11 = 0
La retenue de la colonne suivante est encore zéro.
Et ainsi de suite...Dans la colonne 5 en partant de la droite, les calculs sont :
20 + 9 = 29
29 = 1 $\times$ 17 + 12
1 $\times$ 8 = 8
La retenue de la colonne suivante est 8.

On aboutit finalement à ce tableau complet à la fin de la procédure : attention, le dernier reste dans la colonne « r » est celui de la division euclidienne de somme par 10.

a r 1 2 3 4 5 6 7 8 9 10 11 12
b 3 5 7 9 11 13 15 17 19 21 23 25
décimale dans la base 2 2 2 2 2 2 2 2 2 2 2 2 2
Produit par 10 20 20 20 20 20 20 20 20 20 20 20 20 20
retenue 10 12 12 12 10 12 7 8 9 0 0 0 0
Somme 30 32 32 32 30 32 27 28 29 20 20 20 20
Reste 0 2 2 4 3 10 1 13 12 1 20 20 20

A l’issue de cette première étape, on trouve la partie entière de $\pi$ qui s’obtient en calculant la partie entière du quotient du nombre bleu par 10 puisqu’on cherche en système décimal. C’est bien 3 comme attendu.

On commence la seconde étape : on ne part plus des 2 qui correspondent aux digits dans la base, mais des restes de la dernière ligne du tableau précédent. On initialise toujours retenue à 0, ici en vert.

a r 1 2 3 4 5 6 7 8 9 10 11 12
b 3 5 7 9 11 13 15 17 19 21 23 25
Reste étape 1 0 2 2 4 3 10 1 13 12 1 20 20 20
Produit par 10 0 20 20 40 30 100 10 130 120 10 200 200 200
retenue 13 20 33 40 65 48 98 88 72 150 132 96 0
Somme 13 40 53 80 95 148 108 218 192 160 332 296 200
Reste 3 1 3 3 5 5 4 8 5 8 17 20 0

A l’issue de cette étape, on obtient la première décimale de $\pi$ qui s’obtient en calculant la partie entière du quotient du nombre bleu par 10. C’est bien 1 comme attendu.
On repart de nouveau des restes de l’étape précédente et on initialise retenue à 0.

a r 1 2 3 4 5 6 7 8 9 10 11 12
b 3 5 7 9 11 13 15 17 19 21 23 25
Reste étape 2 3 1 3 3 5 5 4 8 5 8 17 20 0
Produit par 10 30 10 30 30 50 50 40 80 50 80 170 200 0
retenue 11 24 30 40 40 42 63 64 90 120 88 0 0
Somme 41 34 60 70 90 92 103 144 140 200 258 200 0
Reste 1 1 0 0 0 4 12 9 4 10 6 16 0

A l’issue de cette étape, on obtient la deuxième décimale de $\pi$ qui s’obtient en calculant la partie entière du quotient du nombre bleu par 10. C’est bien 4 comme attendu.
On repart de nouveau des restes de l’étape précédente et on initialise retenue à 0.

a r 1 2 3 4 5 6 7 8 9 10 11 12
b 3 5 7 9 11 13 15 17 19 21 23 25
Reste étape 3 1 1 0 0 0 4 12 9 4 10 6 16 0
Produit par 10 10 10 0 0 0 40 120 90 40 100 60 160 0
retenue 4 2 9 24 55 84 63 48 72 60 66 0 0
Somme 14 12 9 24 55 124 183 138 112 160 126 160 0
Reste 4 0 4 3 1 3 1 3 10 8 0 22 0

Ce qui permet de trouver de même une décimale supplémentaire, à savoir 1. Nous en sommes donc à $\pi \simeq 3,141$.
La page internet de Boris Gourévitch permet donc de s’approprier le principe assez facilement. Le caractère très répétitif des calculs et la nature des opérations nécessaires (addition, multiplication, division entière) sont des éléments très rassurants quant à l’écriture d’un programme Python. En effet, il s’agit d’opérations sur des nombres entiers ce qui permettrait d’éviter les soucis de gestion des flottants dont nous avions parlé dans l’article sur les nombres quadratiques.


La réalisation d’un programme $\pi$thon

A ce stade, il est donc facile de produire un programme Python qui automatise la procédure que l’on vient de décrire.
Au départ, on initialise :

  • digit=2
  • r=[] (r contiendra les restes successifs)
  • a=12
  • b=25
  • retenue =0
    On calcule la première somme par somme = digit*10 + retenue.
    On prépare ensuite une boucle "while" qui s’arrêtera lorsque a = 0. A chaque tour de boucle, outre le fait de diminuer a de 1 et b de 2, on calcule :
     le quotient et le reste de la division euclidienne de somme par b.
     la retenue de la colonne suivante en calculant quotient $\times$ a.
     la nouvelle somme de la colonne suivante par somme = digit*10 + retenue
    On stocke également au fur et à mesure tous les restes qui serviront pour initialiser l’étape suivante.
    En sortie de boucle "while", on calcule le quotient et le reste de la dernière somme par 10. Cela permet d’afficher le chiffre de $\pi$ qui a été produit, à savoir ici le "3" de la partie entière.

    1.     digit = 2        #digit dans la base
    2.     r=[]              #création de r, vide, pour accueillir les restes
    3.     a=12            #initialisation de a
    4.     b=25            #initialisation de b
    5.     retenue=0       #initialisation de retenue à 0
    6.     somme = digit*10 + retenue    #calcul de la somme dans la colonne de droite
    7.     while a !=0 :           #tant que a n'est pas 0
    8.         reste = somme % b       #calcul du reste quand on divise par b
    9.         r.append(reste)              #stockage du reste
    10.         quotient = somme //b    #calcul du quotient entier quand on divise par b
    11.         retenue = quotient*a     #calcul de la retenue de la colonne à gauche
    12.         a -=1                   #on enlève 1 à a
    13.         b -=2                   #on enlève 2 à b
    14.         somme = digit*10 + retenue    #calcul de la somme de la colonne à gauche
    15.     #En sortie de boucle while
    16.     print(somme//10)            #on affiche la partie entière de pi
    17.     reste = somme % 10       #on calcule le dernier reste colonne de gauche
    18.     r.append(reste)               #stockage du reste

C’est le moment de partir à l’assaut des décimales derrière la virgule !
Cette fois, on ne part plus de somme = digit*10 + retenue mais on utilise le reste de la première étape situé dans la même colonne. C’est là que les complications commencent. Celui de la colonne de droite est stocké dans "r" en position de r[0]. Celui qui est situé juste à gauche de r[0] est stocké dans r[1] et ainsi de suite....jusqu’au dernier r[12].
On utilise donc un compteur c qui sera chargé d’indiquer la position du reste qui est requis pour le calcul. Et également k qui servira à compter le nombre de décimales déjà produites. Si n est le nombre de décimales à produire, k variera "in range(n)" donc 0 à n-1.

On initialise la boucle sur k par :

  • a=12
  • b=25
  • retenue=0
  • c = 13*k (qui vaut successivement 0,13,26,39...au moment de commencer une nouvelle étape).

Puis on récupère l’architecture de la boucle "while" de la première étape.
Remarque : j’ai délibérément choisi de partir d’un r vide que l’on remplit lors de la première étape, celle qui sert à trouver la partie entière de $\pi$, avant de démarrer une boucle "for". Cela m’a paru plus naturel que de partir d’un "r" contenant 13 fois le nombre 2 et de boucler tout de suite. Cela allonge forcément le programme et donc cela est surtout question de préférences.

On obtient donc ce programme :

  1. def pi(n):          #n est le nombre de chiffres souhaité derrière la virgule
  2.     digit = 2       #digit dans la base
  3.     r=[]            #création de r, vide, pour stocker les restes
  4.     a=12            #initialisation de a
  5.     b=25            #initialisation de b
  6.     retenue=0       #initialisation de retenue à 0
  7.     somme = digit*10 + retenue    #calcul de la somme dans la colonne de droite
  8.     while a !=0 :           #tant que a n'est pas 0
  9.         reste = somme % b       #calcul du reste quand on divise par b
  10.         r.append(reste)         #stockage du reste
  11.         quotient = somme //b    #calcul du quotient entier quand on divise par b
  12.         retenue = quotient*a    #calcul de la retenue de la colonne à gauche
  13.         a -=1                   #on enlève 1 à a
  14.         b -=2                   #on enlève 2 à b
  15.         somme = digit*10 + retenue #calcul de la somme de la colonne à gauche
  16.     #En sortie de boucle while
  17.     print(somme//10)            #on affiche la partie entière de pi
  18.     reste = somme % 10          #on calcule le dernier reste colonne de gauche
  19.     r.append(reste)             #stockage du reste
  20.  
  21.  
  22.     for k in range(n) :     #boucle pour produire n décimales
  23.         a=12                #initialisation de a
  24.         b=25                #initialisation de b
  25.         retenue=0           #initialisation de retenue
  26.         c = 13*k            #initialisation du compteur de rang dans r
  27.         while a !=0 :           #tant que a n'est pas 0
  28.             digit=r[c]          #on récupère le reste du tableau précédent
  29.             somme = digit*10 + retenue      #calcul de la somme
  30.             reste = somme % b             #calcul du reste quand on divise par b
  31.             r.append(reste)               #stockage du reste
  32.             quotient = somme // b         #calcul du quotient entier quand on divise par b
  33.             retenue = quotient*a          #calcul de la retenue de la colonne à gauche
  34.             a -=1                           #on enlève 1 à a
  35.             b -=2                           #on enlève 2 à b
  36.             c +=1                           #on ajoute 1 au compteur de rang
  37.         #En sortie de boucle while
  38.         somme = r[c]*10+retenue     #on calcul la somme de la colonne à gauche
  39.         print(somme//10)            #on affiche la décimale produite
  40.         reste = somme % 10          #on calcule le dernier reste colonne de gauche
  41.         r.append(reste)             #stockage du reste

Quand on appelle pi(3) dans la console Python, on obtient un affichage qui signifie 3,141. Les 3 premières décimales sont conquises. On se sent pousser des ailes et on tape donc pi(5) !
Patatras, les certitudes d’avoir réussi à dompter $\pi$ s’envolent quand apparaît 3,14147 ! Ce n’est pas du tout $\pi$.
$\pi$ètre calculateur, je suis ! Si vous vouliez des rebondissements, vous allez adorer.


Péripétie n°1

C’est la déception donc ! Pourtant après quelques minutes de vérification du code, je suis à peu près convaincu que tout a l’air parfaitement conforme à ce qu’il fallait faire. Serait-ce la série d’Euler qui n’est pas adaptée ? La méthode de Horner qui est ratée ? L’information que ce procédé permet de calculer les décimales de $\pi$ est-elle fiable ? Le doute s’installe. Enfin, pas sur la formule d’Euler quand même ! Alors, je retourne voir le site de Boris Gourévitch.
Et j’y trouve une information ca$\pi$tale que j’avais purement négligée dans une première lecture pour aller directement "à l’essentiel". En fait, le nombre de colonnes de nos tableaux fixe une fois pour toute le nombre de décimales correctes que l’on peut calculer. Ainsi avec nos 13 colonnes de calcul, on ne peut calculer que 3 décimales correctes, soit obtenir 3,141 comme dans l’exemple que nous avons détaillé à la suite de Boris Gourévitch.
En effet, le pas de la base de travail est $\frac{k}{2k+1}$ soit très proche de $\frac{1}{2}$ quand k grandit. Cette base se rapproche donc de ce qu’on obtiendrait pour la base 2.
Pour la conversion de base 2 en base 10, on aurait besoin de $\frac{ln(10)}{ln(2)} \simeq$ 3,32 digits par décimale. On peut considérer que c’est à peu près la même valeur pour notre base à pas variable vers la base 10. Considérons que 3,32 $\simeq \frac{10}{3}$. Pour obtenir 3 décimales derrière la virgule plus la partie entière de $\pi$, il faut donc $\frac{10}{3} \times 4$ soit environ 13 colonnes de calcul dans nos tableaux.
Avec le même raisonnement, on en déduit que pour une décimale de plus derrière la virgule, soit 4, il faut produire des tableaux de 17 colonnes...et pour une décimale supplémentaire 20 colonnes.
La bonne nouvelle, c’est qu’on a compris pourquoi le programme Python était en échec. La mauvaise nouvelle, c’est que la largeur de nos tableaux est variable selon l’objectif. Cela va nous compliquer la quête.
En fait pas tant que ça puisque notre fonction Python "pi" utilise un paramètre $n$ qui correspond au nombre de décimales que l’on souhaite derrière la virgule. Comme l’utilisateur fixe $n$ dès le départ, il est facile pour le programme de calculer le nombre de colonnes adéquat pour atteindre l’objectif prévu. Le programme fonctionne alors dès le début avec un nombre de colonnes fixe et dont la grandeur est adaptée au projet.
On change l’initialisation des variables en début de programme :

  1.     digit=2
  2.     r=[]
  3.     a=4*n
  4.     b=8*n+1
  5.     retenue =0
  6.     somme = digit*10 + retenue

On s’arrange pour avoir en fait $4n+1$ colonnes dans le tableau. Pour 3 décimales, cela fait bien 13 colonnes. Pour 4, on en aura 17 et pour 5, on en aura 21. C’est plus que suffisamment pour assurer la précision de la conversion de base.
On initialise également la boucle "for" sur le même modèle :

  1. for k in range(n) :
  2.         a=4*n
  3.         b=8*n+1
  4.         retenue=0
  5.         c = (4*n+1)*k

Et on passe au test...pi(4) provoque l’affichage attendu à savoir 3,1415. L’appel à pi(5) est lui aussi une réussite, on obtient en effet : 3,14159. On commence à s’enflammer. Le champagne est presque sorti du réfrigérateur quand on tente pi(40).
Et c’est la catastrophe ! Une des décimales produite est "10". C’est un chiffre bizarre !
En réalité, la 31ème décimale est fausse et la 32ème est "10". Mauvaise $\pi$oche ! Décidément, plus on s’approche de $\pi$, plus il semble se dérober.


Péripétie n°2

C’est encore une fois partie remise donc. Par contre, l’erreur commise ressemble à s’y méprendre à un souci avec une retenue. A ces positions de la suite des décimales, on attendait 5 et 0, or le programme Python affiche 4 et 10. D’ailleurs, en réfléchissant bien, Boris Gourévitch avait prévenu que ce genre de difficultés pouvait survenir. Mais dans une première lecture, on avait négligé encore une fois l’information peut-être parce qu’elle apparaissait funeste ou pas très claire tant que le problème ne s’est pas posé :
"Lorsque le reste dans la colonne r est supérieur à 100, on peut trouver (mais c’est rare...) 10 derrière le dernier chiffre que l’on prend pour Pi. On prend alors ce chiffre plus 1 pour décimale de Pi, c’est aussi simple que cela !"
Autrement dit, si il s’affiche 10, il faut corriger le 4 situé juste devant en 5, comme une retenue classique en somme. Cela m’arrangerait !
Pour comprendre véritablement ce qu’il se passe, il est utile d’afficher r et de corriger le programme pour produire une liste s qui stocke les sommes également à chaque étape de calcul.
Voici ce que l’on obtient pour pi(32) quand on ajoute la commande print(s) :
[30, 13, 41, 15, 58, 92, 26, 64, 53, 35, 58, 89, 97, 78, 92, 32, 23, 38, 84, 45, 62, 26, 63, 42, 33, 38, 82, 32, 27, 78, 94, 49, 102]
On sait que les décimales que le programme affiche sont les parties entières du quotient de chaque élément par 10. Il s’affiche donc effectivement :
3,1415926535 8979323846 2643383279 quand arrive le "4" et le "10" malheureux !
Mais Boris Gourévitch a commis une erreur de transcription sur son site, le problème ne vient pas d’un reste supérieur à 100 dans la colonne "r" mais d’une somme supérieure à 100. Auquel cas, évidemment, on n’obtient pas un chiffre en calculant la partie entière du quotient de cette somme par 10. Avec 102, on obtient 10.
En tout cas, il faut ajouter au programme Python une procédure de correction à la toute fin au travers de structures conditionnelles "if...else".
Si la partie entière calculée n’est pas 10, on affiche la décimale produite.
Sinon il faut retourner chercher la décimale d’avant et la corriger en ajoutant 1 (en espérant qu’il ne s’agisse pas d’un 9). Et afficher un zéro pour la décimale suivante.
Si la décimale précédente est "9", elle passe à "10" quand on ajoute, et c’est la décimale d’encore avant qui doit augmenter de 1. Les deux décimales suivantes seront des zéros.
Cela oblige à créer une liste D pour stocker la suite des décimales afin de faciliter la recherche des décimales précédentes. On doit créer aussi un détecteur d’anomalie que l’on mettra à True quand on obtient le cas problématique et à False dans le cas "normal". On l’initialise à false avec anomalie=0 en début de programme. Quand il est passé à True, on rajoute des décimales valant 0 pour remplacer les "10" malheureux.

  1. #écriture de la nouvelle décimale
  2.         if somme // 10 < 10  : #si on obtient un chiffre par la procédure
  3.             d= somme//10       #on calcule la décimale obtenue
  4.             D.append(d)        #on ajoute la décimale dans la liste
  5.             anomalie=0         #on met le détecteur d'anomalie à false
  6.         else :                 #si on n'obtient pas un chiffre
  7.             if d != 9 :         #si la décimale précédente n'est pas 9
  8.                 D[k] += 1      #on ajoute 1 à la décimale précédente
  9.                 anomalie=1     #on met le détecteur d'anomalie à true
  10.             else :              #si la décimale précédente n'est pas 9
  11.                 D[k-1] += 1     #on ajoute 1 à la décimale qui précède la précédente
  12.                 D[k]=0          #on met la décimale précédente à 0
  13.                 anomalie=1     #on met le compteur d'anomalie à true
  14.         if anomalie ==1 : #si une anomalie vient d'être détectée, on ajoute un 0
  15.             D.append(0)
  16.         reste = somme % 10      #on calcule le reste pour l'étape suivante
  17.         r.append(reste)         #on stocke le reste

On notera que D[k] désigne bien la décimale précédente dans la boucle "for" sur k car D[0] est obtenu en dehors de cette boucle et cela décale donc les rangs.

Le test de pi(40) rétablit bien les 40 premières décimales de $\pi$ mais notons que la dernière décimale calculée n’est alors jamais garantie car on a pu stopper le programme juste avant un processus de retenue. C’est ce qui se passe si on appelle pi(31) qui affiche en 31ème et dernière décimale un "4" alors que pi(32) la corrige pour un 5.

Cette procédure de correction fonctionnant à merveille, j’ai repris espoir et les tests suivants se passent bien, très bien. Ils fournissent sans aucun problème des décimales justes.

Les 200 premières décimales de $\pi$

Allez, pi(400) pour la forme !
Je m’aperçois que le cas redouté (celui du "9" devant un "10") arrive autour de la 360ème décimale : les sommes successives sont 58, 89, 103, 35, 59, 99, 100, 10, 12 ce qui aurait dû provoquer l’affichage des "décimales" 5,8,10,3,5,9,10,1,1. Mon programme avec son correctif annonce :
5,9,0,3,6,0,0,1,1.
Ce qui est conforme à ce qui est attendu. Le second "10" a bien provoqué une retenue sur le "9" qui en passant à "10" a induit la transformation du "5" en "6", tout en plaçant des zéros aux bons endroits. Cette fois-ci, c’est parfait !
La 600ème décimale me fait néanmoins une frayeur quand je teste pi(600) mais elle se rétablit avec pi(602) grâce à mon correctif. Ouf !
Je commence même à prévenir mon rédacteur en chef que l’article est en bonne voie. Au moins aller jusqu’à 1000 !! Et patatras !
Forcément dé$\pi$té, j’assiste impuissant à l’affichage de la 854ème décimale qui est fausse et ne se rétablit pas par la suite. Je vois même apparaître un nouveau "10" en appelant pi(857). Le sentiment d’avoir déjà vécu ces instants quelques heures auparavant s’installe. Ma cascade aura au moins produit 853 gouttes...


Péripétie n°3

Le temps de prendre un café pour tenter de prolonger la soirée à la recherche d’une solution, je prends conscience que je commence à avoir une certaine expérience de ces difficultés. En examinant la liste s des différentes sommes, je devrais pouvoir comprendre le problème.
Celle-ci contient successivement entre les rangs 850 et 860 :
70, 9, 100, 9, 99, 99, 102, 30, 13, 37.
Sans le correctif, la liste des décimales aurait donc produit :
7,0,10,0,9,9,10,3,1,3. Autrement dit, effectivement une belle succession de difficultés avec le second 10, précédé de deux 9. Avec le correctif, Python affiche :
7, 1, 0, 0, 10, 0, 0, 3, 1, 3.
Je m’attendais plutôt à trouver les décimales suivantes :
7,1,0,1,0,0,0,3,1,3.
Le correctif a bien fonctionné pour le premier "10", en transformant le "0" qui précède en "1". Mais le second "10" est lui précédé de deux "9", ce que je n’avais pas prévu en effet. La retenue se répercute bien sur la décimale précédente qui est un "9" et passe encore sur la précédente qui devient "10", car je n’avais pas anticipé que cela pouvait être un "9".
Autrement dit, il faut corriger le correctif en enchâssant une nouvelle structure conditionnelle qui teste si la décimale de rang (x-2) est un "9", et si c’est le cas, répercute la retenue sur le rang (x-3) ... en espérant que ce ne soit pas un "9" (mais cela devrait être très rare). Je limite ma correction ainsi :

  1. #écriture de la nouvelle décimale
  2.         if somme // 10 < 10  : #si on obtient un chiffre par la procédure
  3.             d= somme//10       #on calcule la décimale obtenue
  4.             D.append(d)        #on ajoute la décimale dans la liste
  5.             anomalie=0         #on met le détecteur d'anomalie à false
  6.         else :                 #si on n'obtient pas un chiffre
  7.             if d != 9 :
  8.                 D[k] += 1      #on ajoute 1 à la décimale précédente
  9.                 anomalie=1     #on met le détecteur d'anomalie à true
  10.             else :
  11.                 if D[k-1] != 9:
  12.                     D[k-1] += 1    #on ajoute 1 à la décimale juste avant la précédente
  13.                     D[k]=0         #on met la décimale précédente à 0
  14.                     anomalie=1     #on met le détecteur d'anomalie à true
  15.                 else :
  16.                     D[k-2] += 1
  17.                     D[k-1]=0
  18.                     D[k]=0
  19.                     anomalie=1
  20.         if anomalie ==1 : #si une anomalie vient d'être détectée, on ajoute un 0
  21.             D.append(0)

Pour rappel, D[k-2] désigne bien la décimale de rang (x-3), suite au décalage dû à la partie entière. La correction fonctionne impeccablement et quelques instants plus tard, j’ai le plaisir de constater que pi(1000) me fournit 1000 décimales justes de $\pi$. En important time et en ajoutant le calcul de la durée d’exécution, je constate que sur ma machine plutôt ancienne, Python a besoin de 5 secondes pour sortir les 1000 décimales.
Cet algorithme est donc plutôt efficace. Bien moins que les techniques des chercheurs professionnels de décimales, il est vrai, mais c’est quand même assez remarquable.

Je saisis fébrilement pi(5000) et récupère une liste de décimales a priori assez banale environ 75 secondes plus tard. Est-elle correcte ? A première vue rien ne me choque. Mais il convient de vérifier patiemment, ce que je fais pendant quelques jours lors de mes trajets en bus ou en train. J’ai au passage récupéré la liste correcte de 10 000 décimales sur le site de Serge Mehl qui annonce lui 52 secondes de calcul en langage ANSI C en 1995.
J’ai certainement l’air bizarre dans le bus avec mes deux feuilles de tableaux de nombres et mon surligneur aux yeux des autres usagers...Je finis par constater que tout va bien. J’ai bien trouvé 5000 décimales correctes. Je m’y attendais car j’avais pris l’initiative d’ajouter dans le code un détecteur de "chiffres 10" dans la suite des décimales qui n’était jamais passé à True.
J’en suis ravi. Cela me permet de garantir un programme Python qui calcule 5000 décimales justes avec les morceaux de code précédemment cités.
Et je lance alors pi(10000).
C’est le moment où Python tarit définitivement (?) la source de la cascade de décimales en me renvoyant quelques minutes plus tard un message brutal : memory error. Le manque de performance de mon ordinateur en $\pi$teux état se fait sentir !


Péripétie n°4

Le lecteur s’en est peut-être rendu compte, j’ai pour l’instant, été particulièrement prudent avec mon code, en m’offrant des moyens pour déboguer mon programme. Ainsi je stocke tout le long du calcul les valeurs des restes alors qu’elles ne me sont utiles que pour l’étape suivante. En les supprimant au fur et à mesure, on peut libérer de l’espace mémoire et espérer saturer moins vite les capacités de la machine. On écrasera donc les restes à chaque tour de boucle. Pour ce faire, j’utilise une liste auxiliaire "memoire" qui garde les restes en mémoire avant d’écraser la liste r par la commande r =[] qui la vide. De ce fait, plus d’accumulation de données inutiles.
Les premiers tests sont concluants puisque j’arrive bien à retrouver les décimales de $\pi$ correctes et je gagne un peu de temps de calcul sur les 5000 premières qui apparaissent en 1 minutes et 10 secondes soit 5 secondes de gagnées. Et plus le nombre de décimales grandit, plus les bienfaits de la vidange de r devraient se faire sentir.
Je lance alors pi(10000). Il y a bien le risque de tomber sur une séquence de sommes très défavorables avec une accumulation de retenues à un stade non prévu encore dans mon programme, mais sur ce point, j’ai un coup d’avance et je sais que cette éventuelle péripétie n’est pas pour tout de suite normalement.
Au bout de 5 minutes et 27 secondes (même pas eu le temps de finir ma tasse de café), j’ai obtenu les 10 000 décimales espérées dont les dernières sont bien celles prévues. De plus, le programme ne me signale aucune "décimale" erronée valant 10.
Voici le programme adopté pour réaliser ce calcul :

  1. def pi(n):          #n est le nombre souhaité de décimales
  2.     #Obtenir la partie entière de pi
  3.     digit=2         # initialisation de digit à 2 dans la base considérée
  4.     r=[]            # création liste des restes
  5.     memoire=[]      #création d'une liste pour garder en mémoire les restes nécessaires
  6.     D =[]           # création liste des décimales
  7.     a=4*n           # initialisation du nombre a max (ou nombre de colonnes nécessaires)
  8.     b=2*4*n+1       # initialisation du nombre b max
  9.     retenue =0      # initialisation de retenue à 0
  10.     somme = digit*10 + retenue      #calcul de la somme  2*10+retenue
  11.     while a !=0 :       #calculs à rebours vers la colonne de gauche jusqu'à a=1
  12.         reste = somme % b       #on calcule le reste de la division somme : b
  13.         r.append(reste)         #on mémorise le reste dans la liste
  14.         quotient = somme //b    #on calcule le quotient entier de la division somme : b
  15.         retenue = quotient*a    #on calcule la retenue de la colonne suivante
  16.         a -=1                   #on diminue a de 1 pour la colonne suivante
  17.         b -=2                   #on diminue b de 2 pour la colonne suivante
  18.         somme = digit*10 + retenue #on calcule la somme pour la colonne suivante
  19.         #sortie de boucle while
  20.     d=somme//10             #on calcule la décimale obtenue
  21.     D.append(d)             #on ajoute la décimale dans la liste
  22.     reste = somme % 10      #on calcule le reste pour la ligne suivante
  23.     r.append(reste)         #on ajoute le reste dans la liste
  24.     memoire=r               #on garde en mémoire les restes
  25.     r=[]                    #on vide la liste r
  26.     #Obtenir les chiffres derrière la virgule
  27.     anomalie=0              #on initialise le détecteur d'anomalie à false
  28.     for k in range(n) :     #boucle jusqu'au rang n
  29.         a=4*n               # initialisation du nombre a max (ou nombre de colonnes nécessaires)
  30.         b=8*n+1             # initialisation du nombre b max
  31.         retenue=0           # initialisation de retenue à 0
  32.         c = 0               #initialisation du compteur de colonnes
  33.  
  34.         while a !=0 :       #calculs à rebours vers la colonne de gauche jusqu'à a=1
  35.             digit=memoire[c]      # initialisation de digit au reste
  36.             somme = digit*10 + retenue
  37.             reste = somme % b
  38.             r.append(reste)                #on ajoute le reste dans la liste
  39.             quotient = somme // b
  40.             retenue = quotient*a
  41.             a -=1               #on diminue a de 1 pour la colonne suivante
  42.             b -=2               #on diminue b de 2 pour la colonne suivante
  43.             c +=1              #on incrémente le compteur de colonnes
  44.             #sortie de boucle while
  45.         somme = memoire[c]*10+retenue       #on met à jour la somme
  46. #écriture de la nouvelle décimale
  47.         if somme // 10 < 10  :     #si on obtient un chiffre par la procédure
  48.             d= somme//10       #on calcule la décimale obtenue
  49.             D.append(d)          #on ajoute la décimale dans la liste
  50.             anomalie=0           #on met le détecteur d'anomalie à false
  51.         else :                 #si on n'obtient pas un chiffre
  52.             if d != 9 :
  53.                 D[k] += 1      #on ajoute 1 à la décimale précédente
  54.                 anomalie=1     #on met le détecteur d'anomalie à true
  55.             else :
  56.                 if D[k-1] != 9:
  57.                     D[k-1] += 1    #on ajoute 1 à la décimale juste avant la précédente
  58.                     D[k]=0         #on met la décimale précédente à 0
  59.                     anomalie=1     #on met le détecteur d'anomalie à true
  60.                 else :
  61.                     D[k-2] += 1      #on ajoute 1 à la décimale juste avant celle d'avant la précédente....
  62.                     D[k-1]=0
  63.                     D[k]=0
  64.                     anomalie=1
  65.         if anomalie ==1 : #si une anomalie vient d'être détectée, on ajoute un 0
  66.             D.append(0)
  67.  
  68.         reste = somme % 10      #on met à jour le reste pour le k suivant
  69.         r.append(reste)         #on ajoute le reste dans la liste
  70.         memoire=r
  71.         r=[]                    #on vide la liste r
  72.  
  73.     #fin de la boucle for
  74. #Affichage de la valeur approchée de Pi
  75.     print(D)
  76.     for i in range(n) :
  77.         if D[i]== 10 :
  78.             print("problème")

Télécharger

Satisfait de voir reprendre l’écoulement des décimales, je m’oriente tout de suite vers pi(13400) puis pi(17600) car j’ai compris que si nouvelle péripétie il y a, elle devrait se produire aux alentours de la 13 390ème décimale ou de la 17 534ème décimale. Et en effet, pour pi(17600), le programme Python affiche en conclusion dans la console le mot "problème" et je vois bien distinctement une "décimale" égale à 10, comme je le redoutais. Mais cette fois-ci, je ne me sens pas $\pi$toyable car je sais comment résoudre cette difficulté supplémentaire.


Péripétie n°5

En effet, à force de regarder les décimales de $\pi$ dans le bus ou ailleurs, je me suis rendu compte que les différentes péripéties que j’ai rencontrées se repère facilement et sont plus ou moins prévisibles. Parce que les décimales issues de mon programme et qui sont fausses sont toutes dans le développement décimal réel de $\pi$ suivies d’un ou plusieurs zéros. La première fois qu’un zéro y apparaît, c’est à la 32ème décimale soit exactement l’endroit où j’ai dû gérer la péripétie n°2.
Attention, la présence d’un zéro dans le développement décimal ne veut pas forcément dire qu’il y a une anomalie dans le calcul de la décimale à prévoir. Certains zéros viennent tout naturellement de la procédure de calcul classique à savoir "somme // 10" lorsque la somme est strictement inférieure à 10. Mais d’autres zéros sont le produit du correctif (encore manifestement imparfait) que j’ai dû ajouter pour gérer la retenue.
Quant à la péripétie n°3, elle était elle aussi prévisible car il s’agit d’un endroit du développement décimal où se situe la séquence "00" (position 855). Il m’avait alors fallu prolonger le correctif à cause d’une succession de 2 chiffres "9" recevant la retenue.
C’est là où je me suis souvenu de la période où j’étais étudiant en DEA et où j’avais assisté à la conférence de mon professeur Emmanuel Lesigne sur les nombres normaux. Une notion qui est liée à la notion de nombre "univers" initiée par le célèbre Jean-Paul Delahaye en 1996. Un nombre univers est un nombre réel dans les décimales duquel on peut trouver n’importe quelle succession de chiffres de longueur finie, pour une base donnée. Il est probable que $\pi$ soit un nombre univers en base 10 et également un nombre normal. Mais on ne sait pas le prouver.
Néanmoins, il est facile de trouver un très grand nombre de séquence de chiffres dans $\pi$. Par exemple, James Bond, ou du moins son matricule 007, est bien présent dans $\pi$. Il existe sur internet des programmes tout faits qui déterminent la position de la séquence de chiffres recherchée :.
Ainsi, on voit que 007 apparaît en position 2 806. On peut même obtenir les apparitions suivantes.
Mon code postal, 06100, apparaît en position 120 888.
Je n’ai pas trouvé mon numéro de sécurité sociale à 13 chiffres avec ce programme qui ne peut chercher que sur 200 millions de décimales. Si $\pi$ est bien un nombre univers, il devrait apparaître plus tard.
Cette page web me permet donc de repérer des endroits critiques.

Séquence de chiffres Rang de la première apparition Autres apparitions Rang de l’apparition engendrant une anomalie Nombre minimum de "9" successifs
0 32 beaucoup 32 0
00 307 360-601-855 855 1
000 601 855-1598 855 2
0000 13390 17534 17534 3
00000 17534 - 17534 4
000000 1699927 -  ? 5
0000000 3794572 -  ? 6

A moins que je compte obtenir 2 millions de décimales de $\pi$ avec ce programme Python, il ne reste donc plus que la décimale autour du rang 17 534 qui sera digne d’engendrer des péripéties. Nous serions alors dans une situation où 5 zéros de suite seraient produits, avec une retenue qui tombe 4 fois successivement sur un "9". Pour alléger le code, il est peut-être temps de passer à une boucle "while", moment que j’ai retardé le plus possible. Peut être à tort !
Pour ce faire, j’ai créé une variable locale supplémentaire "rang" pour conserver la position du rang de l’anomalie. On teste alors les décimales qui précèdent ce rang. Tant que ce sont des "9", l’anomalie se propage en gardant le compteur à true. Quand celui-ci passe à false, on ajoute 1 à la première décimale qui n’est pas un "9".
Le programme optimisé devient :

  1. def pi(n):          #n est le nombre souhaité de décimales
  2.     #Obtenir la partie entière de pi
  3.     digit=2         # initialisation de digit à 2 dans la base considérée
  4.     r=[]            # création liste des restes
  5.     memoire=[]      #création d'une liste pour garder en mémoire les restes nécessaires
  6.     D =[]           # création liste des décimales
  7.     a=4*n           # initialisation du nombre a max (ou nombre de colonnes nécessaires)
  8.     b=2*4*n+1       # initialisation du nombre b max
  9.     retenue =0      # initialisation de retenue à 0
  10.     somme = digit*10 + retenue      #calcul de la somme  2*10+retenue
  11.     while a !=0 :       #calculs à rebours vers la colonne de gauche jusqu'à a=1
  12.         reste = somme % b       #on calcule le reste de la division somme : b
  13.         r.append(reste)         #on mémorise le reste dans la liste
  14.         quotient = somme //b    #on calcule le quotient de la division somme : b
  15.         retenue = quotient*a    #on calcule la retenue de la colonne suivante
  16.         a -=1                   #on diminue a de 1 pour la colonne suivante
  17.         b -=2                   #on diminue b de 2 pour la colonne suivante
  18.         somme = digit*10 + retenue #on calcule la somme pour la colonne suivante
  19.         #sortie de boucle while
  20.     d=somme//10             #on calcule la décimale obtenue
  21.     D.append(d)             #on ajoute la décimale dans la liste
  22.     reste = somme % 10      #on calcule le reste pour la ligne suivante
  23.     r.append(reste)         #on ajoute le reste dans la liste
  24.     memoire=r               #on garde en mémoire les restes
  25.     r=[]                    #on vide la liste r
  26.     #Obtenir les chiffres derrière la virgule
  27.     anomalie=0              #on initialise le détecteur d'anomalie à false
  28.  
  29.     for k in range(n) :     #boucle jusqu'au rang n
  30.         a=4*n               # initialisation du nombre a max (ou nombre de colonnes nécessaires)
  31.         b=8*n+1             # initialisation du nombre b max
  32.         retenue=0           # initialisation de retenue à 0
  33.         c = 0               #initialisation du compteur de colonnes
  34.  
  35.         while a !=0 :       #calculs à rebours vers la colonne de gauche jusqu'à a=1
  36.             digit=memoire[c]      # initialisation de digit au reste
  37.             somme = digit*10 + retenue
  38.             reste = somme % b
  39.             r.append(reste)     #on ajoute le reste dans la liste
  40.             quotient = somme // b
  41.             retenue = quotient*a
  42.             a -=1               #on diminue a de 1 pour la colonne suivante
  43.             b -=2               #on diminue b de 2 pour la colonne suivante
  44.             c +=1
  45.             #sortie de boucle while
  46.         somme = memoire[c]*10+retenue #on met à jour la somme
  47. #écriture de la nouvelle décimale
  48.         if somme // 10 < 10  : #si on obtient un chiffre par la procédure
  49.             d= somme//10       #on calcule la décimale obtenue
  50.             D.append(d)        #on ajoute la décimale dans la liste
  51.             anomalie=0         #on met le détecteur d'anomalie à false
  52.         else :             #si on n'obtient pas un chiffre
  53.             anomalie = 1        #on a détecté une anomalie
  54.             rang=k              #on conserve le rang du chiffre avant l'anomalie
  55.             D.append(0)         #on met la décimale corerspondante à 0 au lieu de 10
  56.             while anomalie == 1 :  #tant qu'il y a une anomalie
  57.                 if D[rang] != 9 :       #si le chiffre d'avant n'est pas 9
  58.                     anomalie=0          #fin de l'anomalie
  59.                     D[rang] +=1     #on ajoute la retenue 1 au chiffre d'avant
  60.                 else :
  61.                     anomalie=1          #sinon on conserve l'anomalie à true
  62.                     D[rang]=0           #on met la décimale d'avant à 0
  63.                     rang -=1            #on diminue le rang de 1
  64.         reste = somme % 10      #on met à jour le reste pour le k suivant
  65.         r.append(reste)         #on ajoute le reste dans la liste
  66.         memoire=r
  67.         r=[]                    #on vide la liste r
  68.  
  69.     #fin de la boucle for
  70. #Affichage de la valeur approchée de Pi
  71.     print(D)

Télécharger

Il faut veiller à demander 5 décimales supplémentaires pour être certain d’ avoir le bon nombre de décimales qui sont correctes en raison des processus de retenues qui se propagent.
Le programme fonctionne et passe la barre de la 17 534ème décimale sans erreur en environ 20 minutes. Les décimales y sont bien correctes.
Par ailleurs, maintenant que le programme est optimisé, le vidage des restes permet d’aller beaucoup plus loin. pi(50005) aboutit en moins de 2h. Une avancée ca$\pi$tale !
En réalité, l’avantage de cette technique pour calculer $\pi$ est que le temps de calcul sera constant pour sortir toutes les décimales, de la première à la dernière, ce qui n’est pas le cas si on utilise une série qui converge vers $\pi$ : en mettant en œuvre un algorithme de conversion pour passer de la base d’Euler à la base 10, toutes les décimales seront théoriquement calculées au même rythme. Elles nécessitent toutes les mêmes opérations, en même nombre. Si par exemple votre ordinateur vous sort 1 décimale par seconde, il gardera cette cadence de la première décimale jusqu’à la 200 000ème décimale par exemple.


Conclusion

Cet article traite d’un sujet somme toute assez futile puisqu’il s’agit de calculer un grand nombre de décimales de $\pi$ alors que la plupart du temps on se contente de 3,14. La méthode utilisée n’est d’ailleurs pas la plus performante. Néanmoins, l’objectif affiché au départ qui était de montrer que l’usage de l’algorithme de streaming (compte-gouttes) ne se limitait pas à des calculs de radicaux est rempli. On peut d’ailleurs calculer une autre constante essentielle $e$ par un procédé comparable. On pourra consulter le site de Jérôme Cottanceau à cet effet.
Mais finalement, l’article montre aussi ce que sont les mathématiques. Avec son lot de recherches, de $\pi$stes abandonnées, de déboires, d’erreurs, d’insuffisances, de compléments et de corrections ! J’ai, en quelque sorte, essayé de relater ce qui est la norme dans toute recherche mathématique, y compris dans celle des pointures de la discipline, ceux qui sont occupés par les conjectures de Syracuse ou de Riemann par exemple, sujets autrement plus complexes. Eux aussi, passent par des impressions $\pi$égeuses et de sem$\pi$ternels moments de découragement...
Mais c’est bien aussi ce qui en fait le $\pi$ment !