Logarithmes (népériens) des entiers naturels

dimanche 13 juillet 2025



en cours de rédaction


On va voir ici comment calculer (avec un certain nombre de décimales) les valeurs de \(\ln(n)\) pour \(n\) un entier naturel. Écartons de suite (et n'en parlons plus) le cas de \(n = 0\) (pour lequel le logarithme n'existe pas) et le cas de \(n = 1\) (pour lequel on dispose de la formule déjà très précise \(\ln(1) = 0\), suffisante en toute circonstance).

Pour les \(n \geq 2\) on est tenté d'utiliser la série entière \[ \ln(n) = -\ln\!\left(\frac{1}{n}\right) = -\ln\!\left(1 - \frac{n - 1}{n}\right) = \sum_{k = 1}^{+\infty} \frac{1}{k} \times \left(\frac{n - 1}{n}\right)^{\!k}, \] malheureusement les termes ne convergent pas bien vite vers zéro (c'est (hyper-)géométrique, donc ce n'est pas si mal, mais on veut une raison plus petite que \(1/2\)). Alors partons à la recherche de formules plus efficaces.


1 – La fonction argument cotangente hyperbolique

Elle se note \(\mathrm{argcoth}(y)\) (tout un programme), mais commençons par nous rafraîchir la mémoire. Au commencement il y a les fonctions cosinus et sinus hyperboliques \[ \mathrm{ch}(x) = \frac{e^x + e^{-x}}{2} \quad\quad\text{et}\quad\quad \mathrm{sh}(x) = \frac{e^x - e^{-x}}{2} \] à partir desquelles on peut former la cotangente hyperbolique \[ \mathrm{coth}(x) = \frac{\mathrm{ch}(x)}{\mathrm{sh}(x)} = \frac{e^x + e^{-x}}{e^x - e^{-x}}, \] définie dès lors que \(x\) n'est pas égal à zéro. Un calcul facile montre que cosinus et sinus hyperboliques sont chacune la dérivée de l'autre, c'est-à-dire \(\mathrm{ch}'(x) = \mathrm{sh}(x)\) et \(\mathrm{sh}'(x) = \mathrm{ch}(x)\) ; la cotangente hyperbolique est donc dérivable sur son domaine de définition et sa dérivée est donnée par la formule \[ \mathrm{coth}'(x) = \frac{\mathrm{ch}'(x) \mathrm{sh}(x) - \mathrm{ch}(x) \mathrm{sh}'(x)}{\mathrm{sh}(x)^2} = \frac{\mathrm{sh}(x)^2 - \mathrm{ch}(x)^2}{\mathrm{sh}(x)^2} = -\frac{1}{\mathrm{sh}(x)^2}, \] puisque \(\mathrm{ch}(x)^2 - \mathrm{sh}(x)^2 = 1\) (on le vérifie à partir des définitions). La cotangente hyperbolique est donc (strictement) décroissante sur les deux intervalles de son domaine de définition.

(tableau de variation de cotangente hyperbolique)

Soit maintenant \(y \in \left]-\infty\,;\,-1\right[ \;\cup\; \left]1\,;\,+\infty\right[\). Comme on le voit sur le tableau de variations ci-dessus, l'équation \(\mathrm{coth}(x) = y\) possède une solution et une seule, on note cette solution \(x = \mathrm{argcoth}(y)\) et ceci définit une nouvelle fonction \[ \mathrm{argcoth} \;:\; \left]-\infty\,;\,-1\right[ \;\cup\; \left]1\,;\,+\infty\right[ \;\rightarrow\; \mathbf{R} \] qu'on appelle argument cotangente hyperbolique, et qui est la bijection réciproque de la cotangente hyperbolique. Alors ça a l'air compliqué dit comme ça, mézon va voir que cette fonction est en réalité fort sympathique, et pour trois raisons. La première (et sans doute la moins solide) de ces trois raisons est qu'on peut en donner une formule à l'aide du logarithme. En effet \[ \mathrm{argcoth}(y) = x \quad\Leftrightarrow\quad y = \mathrm{coth}(x) \quad\Leftrightarrow\quad y = \frac{e^x + e^{-x}}{e^x - e^{-x}} \] \[ \quad\Leftrightarrow\quad (e^x - e^{-x})y = e^x + e^{-x} \quad\Leftrightarrow\quad e^x(y - 1) = e^{-x}(y + 1) \quad\overset{\times e^x}{\Leftrightarrow}\quad e^{2x}(y - 1) = y + 1 \] \[ \quad\Leftrightarrow\quad e^{2x} = \frac{y + 1}{y - 1} \quad\Leftrightarrow\quad x = \frac{1}{2} \ln\!\left(\frac{y + 1}{y - 1}\right), \] c'est-à-dire qu'on a la

Propriété (expression de l'argument cotangente hyperbolique à partir du logarithme).

Quel que soit le réel \(y \in \left]-\infty\,;\,-1\right[ \;\cup\; \left]1\,;\,+\infty\right[\) on a \[ \mathrm{argcoth}(y) = \frac{1}{2} \ln\!\left(\frac{y + 1}{y - 1}\right). \]



La deuxième raison est que sa dérivée est une fonction très simple (et donc l'argument cotangente hyperbolique surgit lors de nombreux calculs de primitives). Alors on peut calculer cette dérivée à partir de l'expression ci-dessus, mais on va voir une autre méthode importante pour la trouver. On remarque que \(\mathrm{coth}'(x)\) ne s'annule jamais : la bijection réciproque de \(\mathrm{coth}\) est donc dérivable sur son domaine de définition, et on trouve une expression de sa dérivée à partir de la composition \[ \mathrm{coth}(\mathrm{argcoth}(y)) = y \quad\Rightarrow\quad \mathrm{argcoth}'(y) \times \mathrm{coth}'(\mathrm{argcoth}(y)) = 1 \quad\Rightarrow\quad \mathrm{argcoth}'(y) = \frac{1}{\mathrm{coth}'(\mathrm{argcoth}(y))}. \] Et on peut expliciter ça, puisqu'on sait que \(\mathrm{coth}'(x) = -1/\mathrm{sh}(x)^2\), ce qu'ici donne \[ \frac{1}{\mathrm{coth}'(\mathrm{argcoth}(y))} = \frac{1}{\displaystyle{\frac{1}{\mathrm{sh}(\mathrm{argcoth}(y))^2}}} = -\mathrm{sh}(\mathrm{argcoth}(y))^2. \] On craint un temps de n'être point plus avancé, et pourtant \[ \mathrm{sh}(\mathrm{argcoth}(y)) = \mathrm{sh}\!\left(\frac{1}{2}\ln\!\left(\frac{y + 1}{y - 1}\right)\right) = \mathrm{sh}\!\left(\ln\sqrt{\frac{y + 1}{y - 1}}\right) = \frac{\displaystyle{\sqrt{\frac{y + 1}{y - 1}} - \sqrt{\frac{y - 1}{y + 1}}}}{2} \] (on a utilisé les propriétés \(1/2 \times \ln(a) = \ln\sqrt{a}\) et \(-\ln(a) = \ln(1/a)\), et voilà que le logarithme est allé se simplifier avec les exponentielles qui définissent le sinus hyperbolique). Mettons le demi devant pour faire de la place et réduisons ce qui était le numérateur au même dénominateur : \[ = \frac{1}{2} \times \left( \frac{\sqrt{y + 1}\sqrt{y + 1}}{\sqrt{y - 1}\sqrt{y + 1}} - \frac{\sqrt{y - 1}\sqrt{y - 1}}{\sqrt{y + 1}\sqrt{y - 1}} \right) = \frac{1}{2} \times \frac{(y + 1) - (y - 1)}{\sqrt{y - 1} \sqrt{y + 1}} = \frac{1}{2} \times \frac{2}{\sqrt{y^2 - 1}} = \frac{1}{\sqrt{y^2 - 1}}. \] Revenons enfin à la dérivée \[ \mathrm{argcoth}'(y) = -\mathrm{sh}(\mathrm{argcoth}(y))^2 = -\left(\frac{1}{\sqrt{y^2 - 1}}\right)^{\!2} = \frac{1}{1 - y^2}. \] C'est difficile de croire qu'il reste si peu de choses en étant parti d'une définition aussi compliquée (et pourtant l'on sait que le même phénomène se produit avec la fonction arc tangente de la trigonométrie circulaire).

Résumons.

Propriété (dérivée de l'argument cotangente hyperbolique).

La fonction argument cotangente hyperbolique est dérivable sur les deux intervalles de son domaine de définition, et quel que soit le réel \(y \in \left]-\infty\,;\,-1\right[ \;\cup\; \left]1\,;\,+\infty\right[\) on a \[ \mathrm{argcoth}'(y) = \frac{1}{1 - y^2}. \]




2 – Calcul approché

La troisième raison qui fait de l'argument cotangente hyperbolique une fonction sympathique est qu'on dispose d'un algorithme simple pour la calculer. Lorsque \(y \to +\infty\), on a \(1/y^2 \rightarrow 0\) ce qui permet d'utiliser la série entière \[ \mathrm{argcoth}'(y) = \frac{1}{1 - y^2} = -\frac{1}{y^2} \times \frac{1}{\displaystyle{1 - \frac{1}{y^2}}} = -\frac{1}{y^2} \times \sum_{k = 0}^{+\infty} \frac{1}{y^{2k}} = -\sum_{k = 0}^{+\infty} \frac{1}{y^{2k + 2}}. \] Attention on est en puissances de \(1/y\), mais cela ne change rien : il y a convergence normale sur n'importe quel « disque fermé autour de \(+\infty\) », c'est-à-dire sur tout intervalle de la forme \(\left[a\,;\,+\infty\right[\) (avec \(a > 1\)). En intégrant terme à terme, on obtient \[ \mathrm{argcoth}(y) = (\mathrm{cste}) - \sum_{k = 0}^{+\infty} \frac{1}{-(2k + 1)y^{2k + 1}} = (\mathrm{cste}) + \sum_{k = 0}^{+\infty} \frac{1}{(2k + 1)y^{2k + 1}}. \] Puisque \(\mathrm{argcoth}(y) \rightarrow 0\) lorsque \(y \to +\infty\), la constante d'intégration est nulle et voilà une formule étonnamment simple \[ \mathrm{argcoth}(y) = \frac{1}{1y^1} + \frac{1}{3y^3} + \frac{1}{5y^5} + \frac{1}{7y^7} + \ldots. \] Lorsqu'on calcule cette série (à termes positifs !) en s'arrêtant au terme d'indice \(\mathrm{K}\), il reste \[ \sum_{k = \mathrm{K} + 1}^{+\infty} \frac{1}{(2k + 1)y^{2k + 1}} \leq \frac{1}{(2\mathrm{K} + 3)y^{2\mathrm{K} + 3}} \times \sum_{k = 0}^{+\infty} \frac{1}{y^{2k}} = \frac{1}{(2\mathrm{K} + 3)y^{2\mathrm{K} + 3}} \times \frac{1}{\displaystyle{1 - \frac{1}{y^2}}} = \frac{1}{(2\mathrm{K} + 3)y^{2\mathrm{K} + 3}} \times \frac{y^2}{y^2 - 1}. \]

Propriété (algorithme pour calculer l'argument cotangente hyperbolique).

Pour tout nombre \(y\) strictement plus grand que \(1\), on a \[ \mathrm{argcoth}(y) \simeq \sum_{k = 0}^{\mathrm{K}} \frac{1}{(2k + 1)y^{2k + 1}} = \frac{1}{1y^1} + \frac{1}{3y^3} + \frac{1}{5y^5} + \ldots + \frac{1}{(2\mathrm{K} + 1)y^{2\mathrm{K} + 1}}, \] l'erreur commise dans cette approximation (par défaut : la valeur approchée est toujours inférieure à la valeur théorique) étant majorée par \(\displaystyle{\frac{1}{(2\mathrm{K} + 3)y^{2\mathrm{K} + 3}} \times \frac{y^2}{y^2 - 1}}\).


Voyons ce que cela donne en Python. Nous utilisons les nombres décimaux, et en particulier le programme Afficher(x), comme expliqué dans l'article sur les racines. Le programme ci-dessous renvoie une valeur approchée de \(\mathrm{argcoth}(y)\) à \(\epsilon\) près.

# Argument cotangente hyperbolique
def argcoth(y, ε) :
    y_carré = y ** 2
    Q = y_carré / (y_carré - Décimal(1))
    un_sur_y_carré = Décimal(1) / y_carré
    m = 1
    un_sur_y_puissance_m = Décimal(1) / y
    t = un_sur_y_puissance_m / m
    S = Décimal(0)
    while Q * t > ε :
        S += t
        m += 2
        un_sur_y_puissance_m *= un_sur_y_carré
        t = un_sur_y_puissance_m / m
    return S

Testons par exemple \(2 \times \mathrm{argcoth}(3)\).

>>> ε = Décimal(10) ** (-NB_CHIFFRES)
>>> x = 2 * argcoth(Décimal(3), ε)
>>> Afficher(x)
6.931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875420014810205706857336855202357581305570326707516350759619307275708283714351903070386238916734711233501153644979552391204751726815749320651555247341395258829504530070953263666426541042391578149520437404303855008019441706416715186447128399681717845469570262716310645461502572074024816377733896385506952606683411372738737229289564935470257626520988596932019650585547647033067936544325476327449512504060694381471046899465062201677204245245296126879465461931651746813926725041038025462596568691441928716082938031727143677826548775664850856740776484514644399404614226031930967354025744460703080960850474866385231381816767514386674766478908814371419854942315199735488037516586127535291661000710535582498794147295092931138971559982056543928717000721808576102523688921324497138932037843935308877482597017155910708823683627589842589185353024363421436706118923678919237231467232172053401649256872747782344535347 * 10 ** -1

C'est \(\ln(2)\)… et nous verrons bientôt pourquoi.


3 – Trigonométrie hyperbolique

À partir des définitions, on démontre que pour tous réels \(a\) et \(b\) on a \[ \mathrm{ch}(a + b) = \mathrm{ch}(a)\mathrm{ch}(b) + \mathrm{sh}(a)\mathrm{sh}(b) \quad\quad\text{et}\quad\quad \mathrm{sh}(a + b) = \mathrm{sh}(a)\mathrm{ch}(b) + \mathrm{ch}(a)\mathrm{sh}(b) \] (dans les deux cas on part de l'expression la plus compliquée, c'est-à-dire le membre de droite, et on montre qu'il se simplifie en celui de gauche). On en déduit, lorsque \(a\), \(b\) et \(a + b\) sont différents de zéro, que \[ \mathrm{coth}(a + b) = \frac{\mathrm{ch}(a + b)}{\mathrm{sh}(a + b)} = \frac{\mathrm{ch}(a)\mathrm{ch}(b) + \mathrm{sh}(a)\mathrm{sh}(b)}{\mathrm{sh}(a)\mathrm{ch}(b) + \mathrm{ch}(a)\mathrm{sh}(b)} = \frac{\displaystyle{\frac{\mathrm{ch}(a)}{\mathrm{sh}(a)}\frac{\mathrm{ch}(b)}{\mathrm{sh}(b)} + \frac{\mathrm{sh}(a)}{\mathrm{sh}(a)}\frac{\mathrm{sh}(b)}{\mathrm{sh}(b)}}}{\displaystyle{\frac{\mathrm{sh}(a)}{\mathrm{sh}(a)}\frac{\mathrm{ch}(b)}{\mathrm{sh}(b)} + \frac{\mathrm{ch}(a)}{\mathrm{sh}(a)}\frac{\mathrm{sh}(b)}{\mathrm{sh}(b)}}} \] \[ = \frac{\mathrm{coth}(a)\mathrm{coth}(b) + 1}{\mathrm{coth}(b) + \mathrm{coth}(a)} = \frac{1 + \mathrm{coth}(a)\mathrm{coth}(b)}{\mathrm{coth}(a) + \mathrm{coth}(b)}. \] Soient \(\mathrm{A}\) et \(\mathrm{B}\) deux nombres strictement plus grands que \(1\). Il y a donc des nombres \(a\) et \(b\) strictement positifs (et qui vérifient automatiquement les hypothèses faites ci-dessus) tels que \(a = \mathrm{argcoth}(\mathrm{A})\) et \(b = \mathrm{argcoth}(\mathrm{B})\). En substituant il vient \[ \mathrm{coth}(\mathrm{argcoth}(\mathrm{A}) + \mathrm{argcoth}(\mathrm{B})) = \frac{1 + \mathrm{coth}(\mathrm{argcoth}(\mathrm{A}))\mathrm{coth}(\mathrm{argcoth}(\mathrm{B}))}{\mathrm{coth}(\mathrm{argcoth}(\mathrm{A})) + \mathrm{coth}(\mathrm{argcoth}(\mathrm{B}))} = \frac{1 + \mathrm{A}\mathrm{B}}{\mathrm{A} + \mathrm{B}}. \] Puisque c'est la cotangente hyperbolique d'un nombre strictement positif, le résultat est strictement plus grand que \(1\) et on peut lui appliquer l'argument tangente hyperbolique. Et on obtient la

Propriété (formules d'addition et de soustraction pour l'argument tangente hyperbolique).

Pour tous nombres \(\mathrm{A}\) et \(\mathrm{B}\) strictement plus grands que \(1\), on a \[ \mathrm{argcoth}(\mathrm{A}) + \mathrm{argcoth}(\mathrm{B}) = \mathrm{argcoth}\!\left(\frac{1 + \mathrm{A}\mathrm{B}}{\mathrm{A} + \mathrm{B}}\right). \] Si de plus \(\mathrm{A}\) et \(\mathrm{B}\) ne sont pas égaux, on a \[ \mathrm{argcoth}(\mathrm{A}) - \mathrm{argcoth}(\mathrm{B}) = \mathrm{argcoth}\!\left(\frac{1 - \mathrm{A}\mathrm{B}}{\mathrm{A} - \mathrm{B}}\right). \]


Preuve. Il y a encore un peu de travail : on ne peut pas déduire la seconde formule de la première, parce que pour démontrer icelle on a supposé \(\mathrm{B}\) strictement plus grand que \(1\). Reprenons le calcul précédent. Si \(a\), \(b\) et \(a - b\) sont différents de zéro, alors \[ \mathrm{coth}(a - b) = \frac{1 - \mathrm{coth}(a)\mathrm{coth}(b)}{\mathrm{coth}(a) - \mathrm{coth}(b)}. \] Lorsque \(\mathrm{A}\) et \(\mathrm{B}\) ne sont pas égaux, \(a - b\) est différent de zéro et on peut à nouveau faire la substitution \[ \mathrm{coth}(\mathrm{argcoth}(\mathrm{A}) - \mathrm{argcoth}(\mathrm{B})) = \frac{1 - \mathrm{coth}(\mathrm{argcoth}(\mathrm{A}))\mathrm{coth}(\mathrm{argcoth}(\mathrm{B}))}{\mathrm{coth}(\mathrm{argcoth}(\mathrm{A})) - \mathrm{coth}(\mathrm{argcoth}(\mathrm{B}))} = \frac{1 - \mathrm{A}\mathrm{B}}{\mathrm{A} - \mathrm{B}}. \] Et puisque le résultat est l'image d'un nombre par la cotangente hyperbolique, on peut lui appliquer sa réciproque, et ainsi obtenir la seconde formule. C.Q.F.D.



4 – Formules de Machin

John Machin (1680-1751) qui eut parmi ses élèves un certain Brook Taylor (1685-1731), dont nous avons abondamment utilisé les développements en séries plus haut sur cette page… On a rencontré le premier lorsqu'on a calculé les décimales de \(\pi\), et aujourd'hui on appelle plus généralement formule de Machin, en son honneur, tout bricolage permettant d'exprimer une arc tangente comme une combinaison linéaire d'arcs plus petits ou, et on va voir que c'est la même idée, d'exprimer un argument cotangente hyperbolique (donc un logarithme qui s'ignore) comme une combinaison linéaire d'arguments plus grands.

Revenons à \(\mathrm{argcoth}(y) = \displaystyle{\frac{1}{2}\ln\!\left(\frac{y + 1}{y - 1}\right)}\), pour \(y\) strictement plus grand que \(1\). Appelons \(n\) l'argument du logarithme (qui est strictement plus grand que \(1\) lui aussi, puisqu'à l'évidence \(y + 1\) est plus grand que \(y - 1\)). Alors \[ \frac{y + 1}{y - 1} = n \quad\Leftrightarrow\quad y + 1 = (y - 1)n \quad\Leftrightarrow\quad y(n - 1) = n + 1 \quad\Leftrightarrow\quad y = \frac{n + 1}{n - 1}. \] Oui, c'est une involution. Et avec ça on peut déjà expliquer ce qui s'est passé à la fin du paragraphe 2, ce sera notre première formule de Machin : pour \(n = 2\) on a \(y = 2\) et ainsi \[ \frac{1}{2}\ln(2) = \frac{1}{2}\ln\!\left(\frac{3 + 1}{3 - 1}\right) = \mathrm{argcoth}(3) \] qui donne effectivement \(\ln(2) = 2 \times \mathrm{argcoth}(3)\) (et au passage pour les curieux : on a aussi \(\ln(3) = 2 \times \mathrm{argcoth}(2)\), c'est troublant n'est-ce pas ?). Maintenant incorporons à tout cela les formules de trigonométrie de la section précédente. Pour des entiers strictement positifs \(n_{\mathrm{A}}\) et \(n_{\mathrm{B}}\), et pour (toujours) \(\mathrm{A}\) et \(\mathrm{B}\) strictement plus grands que \(1\), on cherche \(y\) (et surtout \(n\)) tel(s) que \[ n_{\mathrm{A}} \times \mathrm{argcoth}(\mathrm{A}) - n_{\mathrm{B}} \times \mathrm{argcoth}(\mathrm{B}) = \mathrm{argcoth}(y), \] c'est-à-dire \(\ln(n) = 2n_{\mathrm{A}} \times \mathrm{argcoth}(\mathrm{A}) - 2n_{\mathrm{B}} \times \mathrm{argcoth}(\mathrm{B})\). Le facteur \(2\) c'est le \(1/2\) dans la formule qui relie l'argument cotangente hyperbolique au logarithme. On va utiliser les nombres rationnels de Python.

from fractions import Fraction

# Formule d'addition des arguments cotangentes hyperboliques
def Opération(A, B) :
    return (1 + A * B) / (A + B)

Le plan de bataille est assez rudimentaire : on essaie plein de valeurs de chaque paramètre, et à chaque fois qu'on tombe sur un \(n\) entier, on affiche. Calculons déjà ce \(n\), pour l'instant rationnel, connaissant les valeurs des quatre paramètres \(n_{\mathrm{A}}\), \(\mathrm{A}\), \(n_{\mathrm{B}}\) et \(\mathrm{B}\).

# Calcule n tel que 1/2 * ln(n) = nA * argcoth(A) - nB * argcoth(B)
def Machiner(nA, A, nB, B) :
    a = Fraction(0)
    for i in range(nA) :
        a = Opération(a, A)
    b = Fraction(0)
    for i in range(nB) :
        b = Opération(b, B)
    if a == b :
        raise Exception("Division par zéro")
    else :
        y = Opération(a, -b)
        return (y + 1) / (y - 1)

Et donc pour savoir si ce rationnel est entier, eh bien on regarde si son dénominateur vaut \(1\) (puisque les fractions sont toujours simplifiées avec un dénominateur strictement positif).

# Teste si le rationnel n est un entier
def EstEntier(n) :
    return n.denominator == 1


Avant de gérer l'affichage, il faut convenir d'une manière de représenter les « formules ». Décidons que la formule \[ \sum_{i} n_i \times \mathrm{argcoth}(i) \] avec des coefficients \(n_i\) rationnels sera représentée par un dictionnaire dont les clés sont les entiers \(i\) (au moins égaux à \(2\)) et les valeurs associées sont les \(n_i\). Commençons par définir les formules à un seul terme.

# Formule constituée d'un seul terme
def Singleton(n_i, i) :
    return {i : Fraction(n_i)}

Définissons quelques opérations : la multiplication par un scalaire…

# Multiplication d'une formule F par un scalaire k
def MultScal(k, F) :
    kF = {}
    for i in F :
        kF[i] = k * F[i]
    return kF

…et la somme. On élimine les termes qui se retrouveraient avec un coefficient nul.

# Construction de la formule F1 + F2
def Combiner(F1, F2) :
    # On part d'une copie de la première formule
    F = dict(F1)
    # Puis on ajoute la seconde
    for i in F2 :
        if i in F :
            F[i] += F2[i]
        else :
            F[i] = F2[i]
    # Suppression des termes nuls
    for i in F :
        if F[i] == 0 :
            del F[i]
    return F


Pour afficher une formule, plus exactement pour la transformer en chaîne de caractères (qu'on pourra, si on le souhaite, afficher avec la fonction print), on convient (arbitrairement) d'écrire d'abord les termes ayant un coefficient positif, puis ceux ayant un coefficient négatif. On va donc parcourir deux fois la formule.

# Conversion d'une formule en chaîne de caractères
def EnChaîne(F) :
    Morceaux = []
    # On commence par les termes positifs...
    for i in F :
        n_i = F[i]
        if n_i > 0 :
            # On met un + avant chaque terme, sauf le premier
            if Morceaux != [] :
                Morceaux.append(" + ")
            # On n'écrit pas le coefficient s'il vaut 1
            if n_i != 1 :
                Morceaux += [str(n_i), " * "]
            Morceaux += ["argcoth(", str(i), ")"]
    # ...puis les termes négatifs
    for i in F :
        n_i = -F[i]
        if n_i > 0 :
            # On met un - avant chaque terme
            Morceaux.append(" - ")
            # On n'écrit pas le coefficient s'il vaut 1
            if n_i != 1 :
                Morceaux += [str(n_i), " * "]
            Morceaux += ["argcoth(", str(i), ")"]
    return "".join(Morceaux)

Testons avec une formule quelconque.

>>> F = Singleton(Fraction(3), 5)
>>> F = Combiner(F, Singleton(Fraction(3, 2), 7))
>>> F = Combiner(F, Singleton(Fraction(-8), 131))
>>> print(EnChaîne(F))
3 * argcoth(5) + 3/2 * argcoth(7) - 8 * argcoth(131)


Maintenant qu'on sait afficher les formules, il faut les fabriquer. On va utiliser une liste de listes BANQUE telle que BANQUE[n] est la liste des formules pour \(\ln(n)\). Si on a au moins une formule pour \(\ln(n)\), il faudra donc que BANQUE soit de longueur au moins \(n + 1\) pour pouvoir l'y ranger.

# Création d'une banque de formules (c'est une liste de listes de formules)
BANQUE = []

# Une formule pour ln(n) doit être ajoutée dans la case n
def AjouterÀLaBanque(n, F) :
    # On ajoute des cases au besoin
    while len(BANQUE) <= n :
        BANQUE.append([])
    BANQUE[n].append(F)

Comme on l'a dit, on va utiliser une technique rudimentaire : on essaie des valeurs des quatre paramètres \(n_{\mathrm{A}}\), \(\mathrm{A}\), \(n_{\mathrm{B}}\) et \(\mathrm{B}\), et à chaque fois qu'on tombe sur le logarithme d'un entier (plutôt qu'un rationnel non entier) on la mémorise. On commence par faire varier \(\mathrm{A}\) et \(\mathrm{B}\) en supposant \(n_{\mathrm{A}}\) et \(n_{\mathrm{B}}\) fixes. On décide arbitrairement de chercher des formules où \(\mathrm{A}\) est strictement plus petit que \(\mathrm{B}\).

# Recherche de formules de Machin
# ln(n) = 2*nA * argcoth(A) - 2*nB * argcoth(B)
MAX__A_PLUS_B = 1_000
def ChercherFormules(nA, nB) :
    Formules = []
    for A in range(2, (MAX__A_PLUS_B + 1) // 2) :
        for B in range(A + 1, MAX__A_PLUS_B + 1 - A) :
            n = Machiner(nA, A, nB, B)
            if EstEntier(n) :
                F = {A : 2 * Fraction(nA), B : -2 * Fraction(nB)}
                Formules.append( (int(n), F) )
    return Formules

Ensuite on remplit la banque avec les formules ainsi obtenues, pour différentes valeurs de \(n_{\mathrm{A}}\) et \(n_{\mathrm{B}}\). Là encore, on décide arbitrairement de ne chercher que des formules où \(n_{\mathrm{B}} = 1\).

# Remplissage de la banque avec des formules à deux termes
def RemplirLaBanque() :
    for nA in range(2, 10 + 1) :
        for nB in range(1, 1 + 1) :
            for (n, F) in ChercherFormules(nA, nB) :
                AjouterÀLaBanque(n, F)

Et on remplit la banque en exécutant une fois pour toutes l'instruction suivante. C'est ce qu'on appelle un précalcul. Attention, suivant les plages de valeurs qu'on a sélectionnées pour les quatre paramètres, ça peut être assez long.

>>> RemplirLaBanque()
Et non seulement c'est long, mais en plus ça n'affiche rien. Écrivons le programme qui permet d'observer le contenu de la banque (une fois qu'elle est remplie). J'appelle formule directe une formule pour \(\ln(n)\) « directement » présente dans la banque (on va en construire d'autres juste après).

# Affichage de toutes les formules pour ln(n) dans la banque
def FormulesDirectes(n) :
    EG = "ln(" + str(n) + ") = "
    for F in BANQUE[n] :
        s = EnChaîne(F)
        print(EG, s, sep = "")

Essayons !

>>> FormulesDirectes(3)
ln(3) = 4 * argcoth(3) - 2 * argcoth(7)
ln(3) = 6 * argcoth(5) - 2 * argcoth(17)


Maintenant on va déduire, de celles qui sont dans la banque (et qui n'ont que deux termes), d'autres formules (avec plus de termes). Et on fait ça parce qu'on remarque qu'avec juste deux termes, il y a moult valeurs de \(n\) pour lesquelles on n'a pas de formule. Première méthode : si \(n = x \times y\), on obtient une nouvelle formule pour \(\ln(n)\) en combinant les formules pour \(\ln(x)\) aux formules pour \(\ln(y)\). Évidemment on a besoin d'un petit programme auxiliaire pour trouver toutes les factorisations de \(n\).

# Liste des couples (x, y) tels que n = x * y (avec x <= y)
def FactorisationsEnDeux(n) :
    Fcts = [] ; x = 2
    while x * x <= n :
        if n % x == 0 :
            Fcts.append( (x, n // x) )
        x += 1
    return Fcts

# Construction de formules en utilisant ln(n) = ln(x) + ln(y)
def FormulesParDessous(n) :
    EG = "ln(" + str(n) + ") = "
    Fcts = FactorisationsEnDeux(n)
    for (x, y) in Fcts :
        for F1 in BANQUE[x] :
            for F2 in BANQUE[y] :
                s = EnChaîne(Combiner(F1, F2))
                print(EG, s, sep = "")

Deuxième méthode, bien plus fructueuse que la précédente (lorsque \(n\) est premier on ne peut pas l'écrire \(x \times y\), et donc il y a toujours des valeurs, par exemple \(n = 11\), pour lesquelles on est sans formule) : on cherche les nombres \(y\) qui ont \(n\) ou une puissance d'icelui en facteur. Si \(n^e \times x = y\) et qu'on a des formules \(\mathscr{F}_x\) et \(\mathscr{F}_y\) pour \(x\) et \(y\) respectivement, alors \[ \frac{1}{e} \times \mathscr{F}_y - \frac{1}{e} \times \mathscr{F}_x \] est une formule pour \(n\), puisque \(\ln(y) = \ln(n^e \times x) = e \times \ln(n) + \ln(x)\).

# Construction de formules en utilisant ln(n ** Exposant) = ln(x) - ln(y)
def FormulesParDessus(n) :
    EG = "ln(" + str(n) + ") = "
    # On cherche les multiples d'une puissance p de n
    p = n ; Exposant = 1
    while p < len(BANQUE) :
        y = 2 ; x = p * y
        while x < len(BANQUE) :
            for F1 in BANQUE[x] :
                F1 = MultScal(Fraction(1, Exposant), F1)
                for F2 in BANQUE[y] :
                    F2 = MultScal(Fraction(-1, Exposant), F2)
                    s = EnChaîne(Combiner(F1, F2))
                    print(EG, s, sep = "")
            y += 1 ; x += p
        p *= n ; Exposant += 1

Et finalement on regroupe les trois algorithmes dans un seul programme pour tout avoir d'un coup.

# Bilan des trois méthodes de constructions
def RésumerFormules(n) :
    FormulesDirectes(n)
    FormulesParDessous(n)
    FormulesParDessus(n)

Testons.

>>> RésumerFormules(10)
ln(10) = 12 * argcoth(5) - 2 * argcoth(17) - 2 * argcoth(161)
ln(10) = 6 * argcoth(3) + 2 * argcoth(7) - 2 * argcoth(31)
ln(10) = 10 * argcoth(3) + 2 * argcoth(17) - 2 * argcoth(31) - 6 * argcoth(5)
ln(10) = 12 * argcoth(3) + 2 * argcoth(5) - 2 * argcoth(31) - 4 * argcoth(2)
ln(10) = 6 * argcoth(3) + 2 * argcoth(7) - 2 * argcoth(31)
ln(10) = 4 * argcoth(2) + 2 * argcoth(17) - 2 * argcoth(161)
ln(10) = 6 * argcoth(3) + 2 * argcoth(7) - 2 * argcoth(31)
ln(10) = 4 * argcoth(2) + 2 * argcoth(17) - 2 * argcoth(161)
ln(10) = 10 * argcoth(2) + 2 * argcoth(7) - 2 * argcoth(161) - 10 * argcoth(3)
ln(10) = 16 * argcoth(3) + 2 * argcoth(17) - 2 * argcoth(31) - 6 * argcoth(2)
ln(10) = 6 * argcoth(3) + 2 * argcoth(7) - 2 * argcoth(31)
ln(10) = 6 * argcoth(3) + 2 * argcoth(7) - 2 * argcoth(31)
ln(10) = 4 * argcoth(2) + 2 * argcoth(17) - 2 * argcoth(161)
ln(10) = 6 * argcoth(3) + 2 * argcoth(7) - 2 * argcoth(31)
ln(10) = 4 * argcoth(2) + 2 * argcoth(17) - 2 * argcoth(161)
ln(10) = 4 * argcoth(2) + 2 * argcoth(17) - 2 * argcoth(161)
ln(10) = 4 * argcoth(2) + 2 * argcoth(17) - 2 * argcoth(161)
ln(10) = 4 * argcoth(2) + 2 * argcoth(17) - 2 * argcoth(161)
>>> RésumerFormules(11)
ln(11) = 5 * argcoth(2) + argcoth(17) - argcoth(485) - 2 * argcoth(5)
ln(11) = 4 * argcoth(2) + argcoth(5) - argcoth(485)
ln(11) = 6 * argcoth(2) + argcoth(7) - argcoth(485) - 3 * argcoth(3)
ln(11) = 4 * argcoth(2) + argcoth(5) - argcoth(485)
ln(11) = 4 * argcoth(2) + argcoth(5) - argcoth(485)
ln(11) = 4 * argcoth(2) + argcoth(5) - argcoth(485)
ln(11) = 4 * argcoth(2) + argcoth(5) - argcoth(485)

Nous n'avons pas cherché à éliminer les doublons, mais ce n'est pas essentiel : pourvu qu'on obtienne au moins une formule, c'est tout ce dont nous avons besoin.


5 – Exemples numériques

Commençons avec \(\ln(10)\). La meilleure formule trouvée, ci-dessus, est \[ \ln(10) = 12 \times \mathrm{argcoth}(5) - 2 \times \mathrm{argcoth}(17) - 2 \times \mathrm{argcoth}(161). \] Si on veut le calculer à \(\epsilon\) près, il faut répartir la tolérance sur les trois termes, et tenir compte des coefficients qui multiplient d'autant les erreurs commises.

>>> ε = Décimal(10) ** (-NB_CHIFFRES)
>>> x1 = argcoth(Décimal(5), ε / (3 * 12))
>>> x2 = argcoth(Décimal(17), ε / (3 * 2))
>>> x3 = argcoth(Décimal(161), ε / (3 * 2))
>>> Afficher(12 * x1 - 2 * x2 - 2 * x3)
2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298341967784042286248633409525465082806756666287369098781689482907208325554680843799894826233198528393505308965377732628846163366222287698219886746543667474404243274365155048934314939391479619404400222105101714174800368808401264708068556774321622835522011480466371565912137345074785694768346361679210180644507064800027750268491674655058685693567342067058113642922455440575892572420824131469568901675894025677631135691929203337658714166023010570308963457207544037084746994016826928280848118428931484852494864487192780967627127577539702766860595249671667418348570442250719796500471495105049221477656763693866297697952211071826454973477266242570942932258279850258550978526538320760672631716430950599508780752371033310119785754733154142180842754386359177811705430982748238504564801909561029929182431823752535770975053956518769751037497088869218020518933950723853920514463419726528728696511086257149219884997

Essayons ensuite \(\ln(11)\) avec la formule \[ \ln(11) = 4 \times \mathrm{argcoth}(2) + \mathrm{argcoth}(5) - \mathrm{argcoth}(485). \] On remarquera qu'on n'a pas d'algorithme pour calculer \(\ln(n)\) : pour chaque valeur particulière de \(n\), on doit trouver une formule ad hoc.

>>> x1 = argcoth(Décimal(2), ε / (3 * 4))
>>> x2 = argcoth(Décimal(5), ε / 3)
>>> x3 = argcoth(Décimal(485), ε / 3)
>>> Afficher(4 * x1 + x2 - x3)
2.397895272798370544061943577965129299821706853937417175218567709130573623913236713075054708002634791414715725888137998522255569158595787395355302390801108065051641906680675096589460667937938246669054663805687286995397166160632902700161137003067683287613032030531894140170576195144338363818297855227496927669504470877233208496728692896139120686029758513552108868824161000176051859758353274158838135949329666358913523348515337495102115063804435037208694365516727697609321162396774832309416627404264952054830496162048980886964867001069466911288161546605716992087405293514900185006511305111972701108228854617248489061200869116356888718693137369069881411147961000865377717628276810278555134316276017559183342864028635155171870799898688324802309587574588779875210615178861713259064245948105149336965395190351169092599812008226719815908589489698246267395013203895848849893892891585182751619288622273660268619374680421650527144129591409761499454775922914722626026961312583766678548711195961707411664919434651