← nimbers
119 fiches
sorte
constante
type
famille

I–XIVPerles

I·1série harmonique alternée
\(\displaystyle\sum_{k=0}^{\infty}\frac{(-1)^k}{k+1}\)
=
\(\ln 2\)
const ln2type sériefamille Σ(−1)ᵏ/(mk+1), m=1
# mpmath, 25 chiffres significatifs
from mpmath import mp, mpf, nsum, inf, ln
mp.dps = 25
s = nsum(lambda k: mpf(-1)**k/(k+1), [0, inf])
print(s)                  # 0.6931471805599453094172321
print(ln(2))              # 0.6931471805599453094172321
I·2série de Leibniz
\(\displaystyle\sum_{k=0}^{\infty}\frac{(-1)^k}{2k+1}\)
=
\(\dfrac{\pi}{4}\)
const πtype sériefamille Σ(−1)ᵏ/(mk+1), m=2 ; β(1)
# Leibniz 1674 — c'est aussi β(1), la fonction β de Dirichlet en 1
from mpmath import mp, mpf, nsum, inf, pi
mp.dps = 25
s = nsum(lambda k: mpf(-1)**k/(2*k+1), [0, inf])
print(s)                  # 0.7853981633974483096156609
print(pi/4)               # 0.7853981633974483096156609
I·3le cas \(m=3\)
\(\displaystyle\sum_{k=0}^{\infty}\frac{(-1)^k}{3k+1}\)
=
\(\dfrac{1}{9}\!\left(\sqrt{3}\,\pi+3\ln 2\right)\)
const mixte π & ln2type sériefamille Σ(−1)ᵏ/(mk+1), m=3
# mélange de deux constantes : π et ln2 réunis
from mpmath import mp, mpf, nsum, inf, pi, ln, sqrt
mp.dps = 25
s   = nsum(lambda k: mpf(-1)**k/(3*k+1), [0, inf])
rhs = (sqrt(3)*pi + 3*ln(2))/9
print(s)                  # 0.8356488482647210533371035
print(rhs)                # 0.8356488482647210533371035
I·4le cas \(m=4\)
\(\displaystyle\sum_{k=0}^{\infty}\frac{(-1)^k}{4k+1}\)
=
\(\dfrac{\pi+2\ln\!\left(1+\sqrt{2}\right)}{4\sqrt{2}}\)
const mixte π & ln(1+√2)type sériefamille Σ(−1)ᵏ/(mk+1), m=4
# la famille continue : chaque m livre sa perle
from mpmath import mp, mpf, nsum, inf, pi, sqrt, ln
mp.dps = 25
s   = nsum(lambda k: mpf(-1)**k/(4*k+1), [0, inf])
rhs = (pi + 2*ln(1 + sqrt(2)))/(4*sqrt(2))
print(s)                  # 0.8669729873399110375739952
print(rhs)                # 0.8669729873399110375739952
II·1problème de Bâle
\(\displaystyle\sum_{n=1}^{\infty}\frac{1}{n^{2}}\)
=
\(\dfrac{\pi^{2}}{6}\)
const πtype sériefamille valeurs de ζ
# Euler 1735 : ζ(2)
from mpmath import mp, zeta, pi
mp.dps = 25
print(zeta(2))            # 1.644934066848226436472415
print(pi**2/6)            # 1.644934066848226436472415
II·2\(\zeta(4)\)
\(\displaystyle\sum_{n=1}^{\infty}\frac{1}{n^{4}}\)
=
\(\dfrac{\pi^{4}}{90}\)
const πtype sériefamille valeurs de ζ
# Euler encore : toutes les ζ(2k) sont des multiples rationnels de π²ᵏ
from mpmath import mp, zeta, pi
mp.dps = 25
print(zeta(4))            # 1.082323233711138191516004
print(pi**4/90)           # 1.082323233711138191516004
II·3série de Bâle alternée
\(\displaystyle\sum_{n=1}^{\infty}\frac{(-1)^{n+1}}{n^{2}}\)
=
\(\dfrac{\pi^{2}}{12}\)
const πtype sériefamille valeurs de ζ, η(2)
# η(2) = (1 − 2¹⁻²)·ζ(2) : alterner divise Bâle par deux
from mpmath import mp, mpf, nsum, inf, pi
mp.dps = 25
s = nsum(lambda n: mpf(-1)**(n+1)/n**2, [1, inf])
print(s)                  # 0.8224670334241132182362076
print(pi**2/12)           # 0.8224670334241132182362076
II·4Bâle sous forme d'intégrale
\(\displaystyle\int_{0}^{1}\frac{-\ln(1-x)}{x}\,dx\)
=
\(\dfrac{\pi^{2}}{6}\)
const πtype intégralefamille valeurs de ζ ; Li₂(1)
# développer −ln(1−x) en série et intégrer terme à terme redonne ζ(2)
from mpmath import mp, quad, log, pi
mp.dps = 25
I = quad(lambda x: -log(1-x)/x, [0, 1])
print(I)                  # 1.644934066848226436472415
print(pi**2/6)            # 1.644934066848226436472415
II·5les impairs de Bâle
\(\displaystyle\sum_{k=0}^{\infty}\frac{1}{(2k+1)^{2}}\)
=
\(\dfrac{\pi^{2}}{8}\)

retirer à \(\zeta(s)\) sa moitié paire \(\zeta(s)/2^{s}\) ne laisse que les impairs : \(\sum_k(2k+1)^{-s}=(1-2^{-s})\,\zeta(s)\) pour \(\operatorname{Re}s>1\). Avec \(s=2\), c'est \(\tfrac34\cdot\tfrac{\pi^{2}}{6}\) ; avec \(s=4\), \(\tfrac{15}{16}\cdot\tfrac{\pi^{4}}{90}=\tfrac{\pi^{4}}{96}\). Contraste saisissant : les mêmes impairs avec des signes alternés donnent \(\sum(-1)^{k}/(2k+1)^{2}=G\), la constante de Catalan (III·1), dont on ne connaît aucune forme close.

const πtype sériefamille valeurs de ζ
# s = 2 à 25 chiffres, s = 4, puis la règle des impairs pour 50 valeurs de s
from mpmath import mp, mpf, nsum, inf, pi, zeta, nstr
import random
mp.dps = 25
random.seed(1)
print(nsum(lambda k: 1/(2*k+1)**2, [0, inf]))# 1.233700550136169827354311
print(pi**2/8)                # 1.233700550136169827354311
print(nstr(nsum(lambda k: 1/(2*k+1)**4, [0, inf]) - pi**4/96, 3))# -2.58e-26
# pour un s quelconque, par un autre chemin : Σ (2k+1)^-s = 2^-s · ζ(s, ½) (Hurwitz)
print(nstr(max(abs(2**-x * zeta(x, mpf(1)/2) - (1 - 2**-x)*zeta(x))# 2.58e-26
               for x in (mpf(random.uniform(1.2, 12)) for _ in range(50))), 3))
II·6Bâle en nombres premiers
\(\displaystyle\prod_{p\ \text{premier}}\frac{1}{1-p^{-2}}\)
=
\(\dfrac{\pi^{2}}{6}\)

la même valeur que II·1, mais construite uniquement avec les nombres premiers : c'est le produit d'Euler (L·47) en \(s=2\). Son inverse, \(\prod_p(1-p^{-2})=6/\pi^{2}\approx0{,}608\), est la probabilité que deux entiers pris au hasard soient premiers entre eux : pour chaque premier \(p\), les deux ne doivent pas être tous deux multiples de \(p\), ce qui arrive avec probabilité \(1-1/p^{2}\) (voir VIII·1 et VIII·2). Le produit converge lentement ; pour les 25 chiffres, le code passe par la fonction zêta des premiers, \(\ln\prod_p=\sum_{k\geq1}P(2k)/k\) avec \(P(s)=\sum_p p^{-s}\).

const πtype produitfamille valeurs de ζ ; nombres premiers
# produits partiels jusqu'à 10², 10⁴, 10⁶ ; puis le produit complet, par la zêta des premiers
N = 10**6
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, int(N**0.5)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
premiers = [q for q in range(N+1) if crible[q]]
from mpmath import mp, mpf, fprod, exp, nsum, inf, primezeta, pi, nstr
mp.dps = 25
partiel = lambda x: fprod(1/(1 - mpf(q)**-2) for q in premiers if q <= x)
print(nstr(partiel(100), 12), nstr(partiel(10**4), 12), nstr(partiel(10**6), 12))# 1.64194519662 1.64491792075 1.64493395536
print(exp(nsum(lambda k: primezeta(2*k)/k, [1, inf])))       # tous les premiers# 1.644934066848226436472415
print(pi**2/6)                # 1.644934066848226436472415
III·1constante de Catalan
\(\displaystyle\sum_{k=0}^{\infty}\frac{(-1)^k}{(2k+1)^{2}}\)
=
\(G\)
const Gtype sériefamille β de Dirichlet, β(2)
# β(2) — on ignore encore si G est irrationnel
from mpmath import mp, mpf, nsum, inf, catalan
mp.dps = 25
s = nsum(lambda k: mpf(-1)**k/(2*k+1)**2, [0, inf])
print(s)                  # 0.9159655941772190150546035
print(catalan)            # 0.9159655941772190150546035
III·2\(\beta(3)\)
\(\displaystyle\sum_{k=0}^{\infty}\frac{(-1)^k}{(2k+1)^{3}}\)
=
\(\dfrac{\pi^{3}}{32}\)
const πtype sériefamille β de Dirichlet, β(3)
# β impair : forme close en π ; β pair (comme G) : aucune connue
from mpmath import mp, mpf, nsum, inf, pi
mp.dps = 30              # 5 chiffres de garde
s   = nsum(lambda k: mpf(-1)**k/(2*k+1)**3, [0, inf])
rhs = pi**3/32
mp.dps = 25
print(s)                  # 0.9689461462593693804836348
print(rhs)                # 0.9689461462593693804836348
III·3Catalan sous forme d'intégrale
\(\displaystyle\int_{0}^{1}\frac{\arctan x}{x}\,dx\)
=
\(G\)
const Gtype intégralefamille β de Dirichlet, β(2)
# arctan x = Σ(−1)ᵏx²ᵏ⁺¹/(2k+1) : on retombe sur III·1
from mpmath import mp, quad, atan, catalan
mp.dps = 25
I = quad(lambda x: atan(x)/x, [0, 1])
print(I)                  # 0.9159655941772190150546035
print(catalan)            # 0.9159655941772190150546035
IV·1produit de Wallis
\(\displaystyle\prod_{n=1}^{\infty}\frac{4n^{2}}{4n^{2}-1}\)
=
\(\dfrac{\pi}{2}\)
const πtype produitfamille Wallis
# Wallis 1656 : le premier produit infini pour π
from mpmath import mp, mpf, nprod, inf, pi
mp.dps = 25
p = nprod(lambda n: (4*n**2)/(4*n**2 - 1), [1, inf])
print(p)                  # 1.570796326794896619231322
print(pi/2)               # 1.570796326794896619231322
IV·2produit de Catalan pour e
\(2\cdot\left(\frac43\right)^{\!1/2}\left(\frac{6\cdot8}{5\cdot7}\right)^{\!1/4}\left(\frac{10\cdot12\cdot14\cdot16}{9\cdot11\cdot13\cdot15}\right)^{\!1/8}\cdots\)
=
\(e\)

Eugène Catalan, 1873 : le même que les nombres de X·2 et la constante G de III·1. On prend les pairs sur les impairs, par blocs qui doublent de taille, avec des exposants qui se divisent par deux. Même allure que Wallis (IV·1), mais c'est \(e\) qui sort, pas \(\pi\). La convergence est lente, l'erreur n'étant divisée que par 2 à chaque bloc : le code calcule donc chaque bloc exactement grâce à \(\Gamma\), pour aller jusqu'au 90ᵉ.

const etype produitfamille Wallis
# 5, 20 puis 90 blocs : la lenteur, puis les 25 chiffres
from mpmath import mp, mpf, loggamma, log, exp, e, nstr
mp.dps = 70                                   # chiffres de garde
# log du produit a·(a+2)·…·b, calculé exactement avec Γ (comme L·17)
lp = lambda a, b: ((b-a)//2 + 1)*log(2) + loggamma(mpf(b)/2 + 1) - loggamma(mpf(a)/2)
def P(K):                                     # les K premiers blocs
    s = log(2)
    for k in range(1, K+1):
        s += (lp(2**k+2, 2**(k+1)) - lp(2**k+1, 2**(k+1)-1)) / 2**k
    return exp(s)
print(nstr(P(5), 25))         # 2.689109944174376163286841
print(nstr(P(20), 25))        # 2.718280930017321431871364
print(nstr(P(90), 25))        # 2.718281828459045235360287
print(nstr(e, 25))            # 2.718281828459045235360287
IV·3produit de Pippenger
\(\left(\frac21\right)^{\!1/2}\left(\frac23\cdot\frac43\right)^{\!1/4}\left(\frac45\cdot\frac65\cdot\frac67\cdot\frac87\right)^{\!1/8}\cdots\)
=
\(\dfrac{e}{2}\)

Nicholas Pippenger, 1980. Même architecture que IV·2, mais chaque impair \(m\) est encadré par ses deux voisins pairs, \((m-1)(m+1)/m^{2}\) : l'erreur est alors divisée par 4 à chaque bloc au lieu de 2. Les facteurs de Wallis (IV·1) sont exactement de la forme \(\frac{2n}{2n-1}\cdot\frac{2n}{2n+1}\) ; ici on inverse le rôle des pairs et des impairs, et les exposants \(1/2^{k}\) changent π en \(e\).

const etype produitfamille Wallis
# 5, 20 puis 50 blocs
from mpmath import mp, mpf, loggamma, log, exp, e, nstr
mp.dps = 70                                   # chiffres de garde
# log du produit a·(a+2)·…·b, calculé exactement avec Γ (comme L·17)
lp = lambda a, b: ((b-a)//2 + 1)*log(2) + loggamma(mpf(b)/2 + 1) - loggamma(mpf(a)/2)
def P(K):
    s = log(2)/2
    for k in range(2, K+1):                    # impairs m entre 2^(k-1) et 2^k
        a, b = 2**(k-1)+1, 2**k-1
        s += (lp(a-1, b-1) + lp(a+1, b+1) - 2*lp(a, b)) / 2**k
    return exp(s)
print(nstr(P(5), 25))         # 1.359362096221469097802607
print(nstr(P(20), 25))        # 1.359140914229728639590219
print(nstr(P(50), 25))        # 1.359140914229522617680144
print(nstr(e/2, 25))          # 1.359140914229522617680144
V·1produit de Viète
\(\frac{\sqrt{2}}{2}\cdot\frac{\sqrt{2+\sqrt{2}}}{2}\cdot\frac{\sqrt{2+\sqrt{2+\sqrt{2}}}}{2}\cdots\)
=
\(\dfrac{2}{\pi}\)
const πtype produitfamille Viète
# Viète 1593 : le plus ancien produit infini de l'histoire
from mpmath import mp, mpf, sqrt, pi
mp.dps = 30              # 5 chiffres de garde
a, p = mpf(0), mpf(1)
for _ in range(60):
    a = sqrt(2 + a)
    p *= a/2
rhs = 2/pi
mp.dps = 25
print(p)                  # 0.6366197723675813430755351
print(rhs)                # 0.6366197723675813430755351
V·2Archimède : les polygones qui doublent
\(\lim_{n\to\infty}2^{\,n-1}\sqrt{2-\sqrt{2+\sqrt{2+\cdots+\sqrt2}}}\)
=
\(\pi\)

avec \(n-1\) racines en tout. C'est le demi-périmètre du polygone régulier à \(2^{n}\) côtés inscrit dans un cercle de rayon 1, soit \(2^{n}\sin(\pi/2^{n})\) : \(2\sqrt2\) pour le carré, puis 3,0615 pour l'octogone, 3,1214, 3,1365… Archimède, en poussant jusqu'à 96 côtés (avec des polygones inscrits et circonscrits), encadrait déjà \(3+\tfrac{10}{71}<\pi<3+\tfrac17\). Sœur de Viète (V·1) : mêmes radicaux imbriqués, en produit chez Viète. Un piège de calcul : sur ordinateur, \(2-\sqrt{2+\cdots}\) soustrait deux nombres presque égaux, et la formule telle quelle se dégrade après une quinzaine de doublements, jusqu'à donner 0. La version stable divise au lieu de soustraire : le côté suivant vaut \(s/\sqrt{2+\sqrt{4-s^{2}}}\).

const πtype limitefamille Viète
# la formule en double précision, sa ruine, la version stable ; puis 60 doublements à 60 chiffres
import math
from mpmath import mp, mpf, sqrt, pi, nstr
def naif(n):                                   # double précision, formule telle quelle
    r = 0.0
    for _ in range(n-2): r = math.sqrt(2 + r)
    return 2**(n-1) * math.sqrt(2 - r)
def stable(n):                                 # côté des 2ⁿ-gones : s ← s / √(2 + √(4 − s²))
    s = math.sqrt(2.0)                         # le carré, n = 2
    for _ in range(n-2): s = s / math.sqrt(2 + math.sqrt(4 - s*s))
    return 2**(n-1) * s
print([round(naif(n), 10) for n in (2, 3, 4, 10, 15)])# [2.8284271247, 3.0614674589, 3.1214451523, 3.1415877253, 3.1415926548]
print(naif(25), naif(28), naif(30))            # l'arrondi dévore tout# 3.142451272494134 3.4641016151377544 0.0
print(stable(30), stable(60)) # 3.141592653589795 3.141592653589795
mp.dps = 60                                    # ou alors beaucoup de chiffres de garde
r = mpf(0)
for _ in range(58): r = sqrt(2 + r)
print(nstr(2**59 * sqrt(2 - r), 25))# 3.141592653589793238462643
print(nstr(pi, 25))           # 3.141592653589793238462643
VI·1\(\operatorname{Li}_1\!\left(\tfrac12\right)\)
\(\displaystyle\sum_{n=1}^{\infty}\frac{1}{n\,2^{n}}\)
=
\(\ln 2\)
const ln2type sériefamille polylogarithme, Li₁(1/2)
# −ln(1−x) en x = 1/2 : converge bien plus vite que I·1
from mpmath import mp, mpf, nsum, inf, ln
mp.dps = 25
s = nsum(lambda n: 1/(n*mpf(2)**n), [1, inf])
print(s)                  # 0.6931471805599453094172321
print(ln(2))              # 0.6931471805599453094172321
VI·2\(\operatorname{Li}_2\!\left(\tfrac12\right)\)
\(\displaystyle\sum_{n=1}^{\infty}\frac{1}{n^{2}\,2^{n}}\)
=
\(\dfrac{\pi^{2}}{12}-\dfrac{\ln^{2}2}{2}\)
const mixte π & ln2type sériefamille polylogarithme, Li₂(1/2)
# Euler, via la réflexion Li₂(x) + Li₂(1−x) = ζ(2) − ln x·ln(1−x)
from mpmath import mp, mpf, nsum, inf, pi, ln
mp.dps = 25
s   = nsum(lambda n: 1/(n**2*mpf(2)**n), [1, inf])
rhs = pi**2/12 - ln(2)**2/2
print(s)                  # 0.5822405264650125059026563
print(rhs)                # 0.5822405264650125059026563
VII·1intégrale de Gauss
\(\displaystyle\int_{0}^{\infty}e^{-x^{2}}\,dx\)
=
\(\dfrac{\sqrt{\pi}}{2}\)
const πtype intégralefamille intégrales célèbres
# le carré de l'intégrale se calcule en coordonnées polaires
from mpmath import mp, quad, exp, sqrt, pi, inf
mp.dps = 25
I = quad(lambda x: exp(-x**2), [0, inf])
print(I)                  # 0.8862269254527580136490837
print(sqrt(pi)/2) # 0.8862269254527580136490837
VII·2intégrale de Serret
\(\displaystyle\int_{0}^{1}\frac{\ln(1+x)}{1+x^{2}}\,dx\)
=
\(\dfrac{\pi\ln 2}{8}\)
const mixte π & ln2type intégralefamille intégrales célèbres
# Serret 1844 : x = tan θ, puis la symétrie θ ↦ π/4 − θ
from mpmath import mp, quad, log, pi
mp.dps = 25
I = quad(lambda x: log(1+x)/(1+x**2), [0, 1])
print(I)                  # 0.2721982612879502663125861
print(pi*log(2)/8)# 0.2721982612879502663125861
VIII·1sommes de l'indicatrice d'Euler
\(\displaystyle\lim_{n\to\infty}\frac{n\sqrt{3}}{\sqrt{\varphi(1)+\varphi(2)+\cdots+\varphi(n)}}\)
=
\(\pi\)
const πtype limitefamille indicatrice φ
# pas de 25 chiffres ici : l'erreur relative décroît en O(log n / n).
# φ(1)+…+φ(n) ~ 3n²/π², car deux entiers au hasard sont premiers
# entre eux avec probabilité 6/π². On regarde donc la convergence.
from math import sqrt, pi
N = 10**6
phi = list(range(N+1))
for p in range(2, N+1):
    if phi[p] == p:                  # p est premier
        for m in range(p, N+1, p):
            phi[m] -= phi[m] // p
S = 0
for n in range(1, N+1):
    S += phi[n]
    if n in (10**3, 10**4, 10**5, 10**6):
        print(n, n*sqrt(3)/sqrt(S))
print(pi)
# 1000    3.140412759431513
# 10000   3.141534213179507
# 100000  3.1415847755808897
# 1000000 3.1415926460191628   (7 chiffres justes)
# π       3.141592653589793
VIII·2série de Möbius, inverse de \(\zeta(2)\)
\(\displaystyle\sum_{n=1}^{\infty}\frac{\mu(n)}{n^{2}}\)
=
\(\dfrac{6}{\pi^{2}}\)
const πtype sériefamille Möbius μ ; 1/ζ(2)
# la somme partielle converge lentement (≈ 9 chiffres à 10⁶) ;
# l'égalité exacte vient de Σ μ(n)/nˢ = 1/ζ(s), vérifiée à 25 chiffres.
# C'est aussi la densité des couples premiers entre eux (voir VIII·1).
from math import fsum
from mpmath import mp, zeta, pi
N = 10**6
mu, prime = [1]*(N+1), [True]*(N+1)
for p in range(2, N+1):
    if prime[p]:
        for m in range(2*p, N+1, p): prime[m] = False
        for m in range(p, N+1, p):   mu[m] = -mu[m]
        for m in range(p*p, N+1, p*p): mu[m] = 0
print(fsum(mu[n]/n**2 for n in range(1, N+1)))# 0.6079271020404619
mp.dps = 25
print(1/zeta(2))          # 0.6079271018540266286632768
print(6/pi**2)            # 0.6079271018540266286632768
VIII·3le PPCM de 1 à n grandit comme eⁿ
\(\displaystyle\lim_{n\to\infty}\operatorname{ppcm}(1,2,\dots,n)^{1/n}\)
=
\(e\)

le logarithme du PPCM est la seconde fonction de Chebyshev : \(\ln\operatorname{ppcm}(1,\dots,n)=\psi(n)=\sum_{m\leq n}\Lambda(m)\), car chaque premier \(p\) y figure avec l'exposant \(\lfloor\log_p n\rfloor\), un par puissance \(p^{k}\leq n\) (voir L·30). Par exemple \(\operatorname{ppcm}(1,\dots,10)=2^{3}\cdot3^{2}\cdot5\cdot7=2520\) et \(\psi(10)=\ln2520\). Dire que \(\psi(n)/n\to1\), c'est exactement le théorème des nombres premiers (1896) ; Chebyshev avait déjà encadré ce rapport entre 0,92 et 1,11 vers 1850. Sa sœur, \(\theta(x)=\ln(x\#)\) avec la primorielle \(x\#\) (produit des premiers jusqu'à \(x\)), tend vers 1 de la même façon. C'est aussi pourquoi les dénominateurs de \(H_n\) grandissent comme \(e^{n}\) (L·36).

const etype limitefamille nombres premiers ; fonctions arithmétiques
# ppcm(1..10) ; ψ et θ jusqu'à un million ; puis ppcm(1..1000)^(1/1000) calculé exactement
N = 10**6
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, int(N**0.5)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
premiers = [q for q in range(N+1) if crible[q]]
from math import lcm, log, exp
from functools import reduce
from mpmath import mp, mpf, e, nstr
mp.dps = 25
print(reduce(lcm, range(1, 11)))# 2520
psi = lambda x: sum(log(q) * int(log(x)/log(q) + 1e-12) for q in premiers if q <= x)
theta = lambda x: sum(log(q) for q in premiers if q <= x)
print([round(exp(psi(x)/x), 5) for x in (10**2, 10**4, 10**6)])# [2.56114, 2.72193, 2.71716]
print([round(theta(x)/x, 5) for x in (10**2, 10**4, 10**6)])# [0.83728, 0.9896, 0.99848]
print(nstr(mpf(reduce(lcm, range(1, 1001)))**(mpf(1)/1000), 8), nstr(e, 8))# 2.7092746 2.7182818
IX·1somme des boules de dimension paire
\(\displaystyle\sum_{k=0}^{\infty}V_{2k}(1)\)
=
\(e^{\pi}\)

car \(V_{2k}(1)=\pi^{k}/k!\) : la série de l'exponentielle fait le reste. \(e^{\pi}\) est la constante de Gelfond, dont on sait qu'elle est transcendante.

const e^πtype sériefamille boules et sphères
# mpmath, 25 chiffres significatifs
from mpmath import mp, mpf, pi, gamma, nsum, inf, exp
mp.dps = 25
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n
s = nsum(lambda k: V(2*k), [0, inf])
print(s)                  # 23.14069263277926900572909
print(exp(pi))            # 23.14069263277926900572909
IX·2\(\Gamma(\tfrac12)\)
\(\displaystyle\int_{0}^{\infty}\frac{e^{-t}}{\sqrt t}\,dt\)
=
\(\sqrt{\pi}\)

c'est \(\Gamma(\tfrac12)\). Avec \(t=x^{2}\), on retombe sur deux fois l'intégrale de Gauss (VII·1). C'est par là que \(\sqrt\pi\) entre dans le volume des boules de dimension impaire.

const πtype intégralefamille boules et sphères ; Gauss
# quadrature directe gênée par la singularité en 0 : on pose t = eᵘ,
# ce qui donne une fonction lisse ; les queues au-delà de [−140, 5]
# pèsent moins de 10⁻²⁵.
from mpmath import mp, quad, exp, sqrt, pi
mp.dps = 25
I = quad(lambda u: exp(u/2 - exp(u)), [-140, 0, 5])
print(I)                  # 1.772453850905516027298167
print(sqrt(pi))           # 1.772453850905516027298167
IX·3la boule dans son cube, dimensions paires
\(\displaystyle\sum_{k=0}^{\infty}V_{2k}\!\left(\tfrac12\right)\)
=
\(e^{\pi/4}\)

chaque terme est la part du cube unité remplie par sa boule inscrite, de rayon \(\tfrac12\) : 78,5 % du carré, 52,4 % du cube, 0,25 % en dimension 10. Comme \(V_{2k}(\tfrac12)=(\pi/4)^{k}/k!\), la somme vaut \(e^{\pi/4}\) ; plus généralement \(\sum_k V_{2k}(r)=e^{\pi r^{2}}\), et IX·1 est le cas \(r=1\).

const e^πtype sériefamille boules et sphères ; hypercubes
# mpmath, 25 chiffres significatifs
from mpmath import mp, mpf, pi, gamma, nsum, inf, exp
mp.dps = 25
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n
s = nsum(lambda k: V(2*k, mpf(1)/2), [0, inf])
print(s)                  # 2.19328005073801545655977
print(exp(pi/4))          # 2.19328005073801545655977
X·1Dobinski : les nombres de Bell cachés dans e
\(\displaystyle\sum_{k=0}^{\infty}\frac{k^{3}}{k!}\)
=
\(5e\)

c'est le cas \(n=3\) de la formule de Dobinski (1877), \(\sum_{k} k^{n}/k! = e\,B_n\), où \(B_n\) est le nombre de Bell : le nombre de façons de répartir \(n\) objets en groupes. Il y en a 5 pour 3 objets : {abc}, {ab|c}, {ac|b}, {bc|a}, {a|b|c}. Le code compte ces répartitions une par une, puis vérifie la formule pour \(n=1\) à 6.

const etype sériefamille comptage
# Bell compté par énumération, puis Dobinski à 25 chiffres
def partitions(elems):                        # toutes les partitions d'un ensemble
    if not elems:
        yield []
        return
    x, reste = elems[0], elems[1:]
    for p in partitions(reste):
        yield [[x]] + p                           # x seul dans un bloc
        for i in range(len(p)):                   # ou x rejoint un bloc
            yield p[:i] + [[x] + p[i]] + p[i+1:]
from mpmath import mp, nsum, factorial, inf, e
mp.dps = 25
B = [sum(1 for _ in partitions(list(range(n)))) for n in range(7)]
print(B)                      # [1, 1, 2, 5, 15, 52, 203]
print(all(abs(nsum(lambda k: k**n/factorial(k), [0, inf]) - e*B[n]) < 1e-20# True
          for n in range(1, 7)))
print(nsum(lambda k: k**3/factorial(k), [0, inf]))# 13.59140914229522617680144
print(5*e)                    # 13.59140914229522617680144
X·2inverses des nombres de Catalan
\(\displaystyle\sum_{n=0}^{\infty}\frac{1}{C_n}\)
=
\(2+\dfrac{4\sqrt3\,\pi}{27}\)

où \(C_n=\binom{2n}{n}/(n+1)\) : 1, 1, 2, 5, 14, 42… Les nombres de Catalan comptent les parenthésages, les arbres binaires, les partitions non croisées, les chemins qui ne passent jamais sous l'horizon. Leurs inverses, sommés, font surgir \(\pi\) et \(\sqrt3\).

const πtype sériefamille comptage
# mpmath, 25 chiffres significatifs
from mpmath import mp, nsum, binomial, inf, pi, sqrt
mp.dps = 25
C = lambda n: binomial(2*n, n)/(n+1)
print([int(C(n)) for n in range(8)])# [1, 1, 2, 5, 14, 42, 132, 429]
print(nsum(lambda n: 1/C(n), [0, inf]))# 2.806133050770763489152924
print(2 + 4*sqrt(3)*pi/27)    # 2.806133050770763489152924
X·3inverses des binomiaux centraux
\(\displaystyle\sum_{n=0}^{\infty}\binom{2n}{n}^{-1}\)
=
\(\dfrac43+\dfrac{2\sqrt3\,\pi}{27}\)

\(\binom{2n}{n}\) compte les chemins de \(n\) pas vers la droite et \(n\) vers le haut : 1, 2, 6, 20, 70… Sœur de X·2, avec le même \(\sqrt3\,\pi/27\), à un facteur 2 près : Catalan n'est qu'un binomial central divisé par \(n+1\).

const πtype sériefamille comptage
# mpmath, 25 chiffres significatifs
from mpmath import mp, nsum, binomial, inf, pi, sqrt, mpf
mp.dps = 25
print(nsum(lambda n: 1/binomial(2*n, n), [0, inf]))# 1.736399858718715077909795
print(mpf(4)/3 + 2*sqrt(3)*pi/27)# 1.736399858718715077909795
X·4Fubini : ln 2 au bout des classements
\(\displaystyle\lim_{n\to\infty}\frac{n\,a_{n-1}}{a_n}\)
=
\(\ln 2\)

où \(a_n\) est le nombre de Fubini : les classements de \(n\) concurrents, ex æquo permis (1, 1, 3, 13, 75, 541…). Il croît comme \(n!/\bigl(2(\ln2)^{n+1}\bigr)\), et la convergence est fulgurante : l'erreur est divisée par environ 9 à chaque cran. Comme Bell (X·1), il a sa formule à la Dobinski : \(a_n=\sum_{k} k^{n}/2^{k+1}\).

const ln2type limitefamille comptage
# valeurs exactes par récurrence, puis convergence du rapport
from math import comb
from mpmath import mp, mpf, ln, nsum, inf
mp.dps = 25
a = [1]
for n in range(1, 61):                            # on choisit d'abord les premiers ex æquo
    a.append(sum(comb(n, k)*a[n-k] for k in range(1, n+1)))
print(a[:8])                  # [1, 1, 3, 13, 75, 541, 4683, 47293]
print(nsum(lambda k: k**4/mpf(2)**(k+1), [0, inf]))# 75.0
r = lambda n: mpf(n*a[n-1])/a[n]
print(r(5))                   # 0.6931608133086876155268022
print(r(10))                  # 0.6931471804369557443633155
print(r(20))                  # 0.6931471805599453093587796
print(r(60))                  # 0.6931471805599453094172321
print(ln(2))                  # 0.6931471805599453094172321
X·5formule de Stirling
\(\displaystyle\lim_{n\to\infty}\frac{n!}{\sqrt{n}\,\left(n/e\right)^{n}}\)
=
\(\sqrt{2\pi}\)

autrement dit \(n!\approx\sqrt{2\pi n}\,(n/e)^{n}\). De Moivre trouve la forme vers 1730 ; Stirling identifie la constante \(\sqrt{2\pi}\), grâce au produit de Wallis (IV·1, et L·27 pour le mécanisme). En version logarithmique, \(\ln n! = n\ln n - n + \tfrac12\ln(2\pi n) + \tfrac{1}{12n} - \tfrac{1}{360n^{3}} + \dots\) : les corrections viennent de la formule d'Euler–Maclaurin et sont faites des nombres de Bernoulli de L·25. C'est d'elle que sortent le pic en dimension 5 et la formule d'A121546.

const πtype limitefamille comptage
# convergence lente en 1/(12n) ; corrigée par Euler–Maclaurin, elle devient fulgurante
from mpmath import mp, mpf, loggamma, log, exp, sqrt, pi
mp.dps = 25
r = lambda n: exp(loggamma(n+1) - log(n)/2 - n*log(n) + n)
print(r(10))                  # 2.52759712035971761410261
print(r(1000))                # 2.506837169017401820105396
print(r(10**6))               # 2.506628483516698758337376
print(r(10**6)*exp(-1/(12*mpf(10)**6)))       # 1er terme d'Euler–Maclaurin# 2.506628274631000502183361
print(sqrt(2*pi))             # 2.506628274631000502415765
XI·1la base des logarithmes
\(\displaystyle\sum_{n=0}^{\infty}\frac{1}{n!}\)
=
\(e\)

le cas \(b=e\), \(x=1\) de la série de l'antilogarithme (L·28) : la base des logarithmes naturels, écrite comme une somme. C'est la plus rapide des formules pour \(e\) : 10 termes donnent 6 chiffres, 30 en donnent plus de 25. En alternant les signes, \(\sum(-1)^{n}/n!=1/e\) : c'est la probabilité qu'en distribuant des lettres au hasard, aucune n'arrive à son destinataire (les « dérangements », que le code compte pour 8 lettres).

const etype sériefamille logarithmes ; comptage
# 10 puis 30 termes ; puis les dérangements de 8 lettres, comptés un par un
from itertools import permutations
from math import factorial as fact
from mpmath import mp, mpf, factorial, e
mp.dps = 30                                    # chiffres de garde pour les sommes
s10 = sum(1/factorial(mpf(n)) for n in range(10))
s30 = sum(1/factorial(mpf(n)) for n in range(30))
mp.dps = 25
print(s10)                    # 2.718281525573192239858907
print(s30)                    # 2.718281828459045235360287
print(e)                      # 2.718281828459045235360287
d = sum(1 for p in permutations(range(8)) if all(p[i] != i for i in range(8)))
print(mpf(d)/fact(8))         # 0.3678819444444444444444444
print(1/e)                    # 0.3678794411714423215955238
XI·2la constante d'Euler, entre logarithme et série harmonique
\(\displaystyle\sum_{b=2}^{\infty}\left(\ln\frac{b}{b-1}-\frac1b\right)\)
=
\(1-\gamma\)

tirée de \(\ln(b-1)-\ln b=\ln\bigl(1-\tfrac1b\bigr)\) : en sommant pour \(b=2,\dots,n\), les logarithmes se simplifient en cascade et laissent \(\ln n\) ; en retranchant la série harmonique \(\tfrac12+\dots+\tfrac1n\), il reste \(1-\gamma\). Chaque terme est l'aire d'un petit croissant, entre la courbe \(1/x\) et le rectangle de hauteur \(1/b\) posé sur \([b-1,b]\). \(\gamma\approx0{,}5772\) est la constante d'Euler–Mascheroni, l'écart entre la série harmonique et le logarithme ; on ne sait même pas si elle est irrationnelle. Attention au cas \(b=1\) : \(\ln 0\) n'existe pas, d'où le départ en \(b=2\).

const γtype sériefamille logarithmes
# mpmath, 25 chiffres ; puis la convergence lente de la définition de γ
from mpmath import mp, nsum, log, inf, euler, harmonic
mp.dps = 25
s = nsum(lambda b: log(b/(b-1)) - 1/b, [2, inf])
print(s)                      # 0.4227843350984671393934879
print(1 - euler)              # 0.4227843350984671393934879
# la même constante, vue lentement : 1 + 1/2 + … + 1/n − ln n → γ
print(harmonic(10**6) - log(10**6))# 0.5772161649014495272731789
print(euler)                  # 0.5772156649015328606065121
XII·1l'identité d'Euler
\(e^{i\pi}+1\)
=
\(0\)

cinq constantes, \(e\), \(i\), \(\pi\), 1 et 0, dans une seule égalité. C'est le cas \(x=\pi\) de la formule d'Euler (L·33) : \(e^{i\pi}=\cos\pi+i\sin\pi=-1\). Et comme \(-1=i^{2}\), on a aussi \(\cos(n\pi)=(-1)^{n}=(i^{2})^{n}\) pour tout entier \(n\). On peut aussi la voir comme la série de l'antilogarithme (L·28) avec un exposant imaginaire : \(\sum_k (i\pi)^{k}/k!=-1\).

const mixtetype valeur exactefamille exponentielle complexe
# e^{iπ} + 1, puis la série de l'exponentielle, puis cos(nπ) = (i²)ⁿ
from mpmath import mp, exp, pi, j, cos, nsum, factorial, inf, nstr
mp.dps = 25
print(nstr(abs(exp(j*pi) + 1), 3))              # zéro, au bruit d'arrondi près# 1.88e-26
print(nstr(nsum(lambda k: (j*pi)**k/factorial(k), [0, inf]), 20))# (-1.0 - 4.1642941483854355195e-54j)
print(all(abs(cos(n*pi) - (j**2)**n) < 1e-20 for n in range(-10, 11)))# True
XII·2cos(π/5) et le nombre d'or
\(\cos\dfrac{\pi}{5}\)
=
\(\dfrac{1+\sqrt5}{4}\)

c'est la moitié du nombre d'or \(\varphi=(1+\sqrt5)/2\), qui gouverne le pentagone régulier. Les dix nombres \(e^{i\pi n/5}\), pour \(n=0\) à 9, sont les racines dixièmes de l'unité, les sommets d'un décagone (L·34) ; le premier vaut \(e^{i\pi/5}=\tfrac{1+\sqrt5}{4}+i\,\tfrac{\sqrt{10-2\sqrt5}}{4}\). Pour les angles \(\pi/n\), de telles formes en radicaux n'existent que pour certains \(n\) : 3, 4, 5, 6, 8, 10, 12, 15, 16, 17… (Gauss).

const nombre d'ortype valeur exactefamille exponentielle complexe
# mpmath, 25 chiffres ; puis e^{iπ/5} en radicaux
from mpmath import mp, cos, sin, exp, pi, j, sqrt, nstr
mp.dps = 25
print(cos(pi/5))              # 0.8090169943749474241022934
print((1+sqrt(5))/4)          # 0.8090169943749474241022934
print(nstr(abs(exp(j*pi/5) - ((1+sqrt(5))/4 + j*sqrt(10-2*sqrt(5))/4)), 3))# 0.0
XII·3i puissance i
\(i^{\,i}\)
=
\(e^{-\pi/2}\)

un imaginaire élevé à une puissance imaginaire donne un nombre réel : \(i^{i}=e^{i\ln i}=e^{i\cdot i\pi/2}=e^{-\pi/2}\approx0{,}2079\). C'est aussi \(1/\sqrt{e^{\pi}}\), l'inverse de la racine de la constante de Gelfond (IX·1), et donc un nombre transcendant (Gelfond, 1929) : les fractions ne peuvent que l'approcher, comme \(537842140/2587277449\), juste à 19 chiffres. Comme \(i=e^{i(\pi/2+2\pi n)}\) pour tout entier \(n\), \(i^{i}\) a en réalité une infinité de valeurs, toutes réelles : \(e^{-\pi/2-2\pi n}\). Au passage, \(\log_i x=\ln x/\ln i=2\ln x/(i\pi)\).

const e^πtype valeur exactefamille exponentielle complexe
# la valeur principale, trois autres branches, deux approximations, puis log_i
from mpmath import mp, mpf, j, pi, exp, sqrt, log, nstr
mp.dps = 25
print(j**j)                   # (0.2078795763507619085469556 + 0.0j)
print(exp(-pi/2))             # 0.2078795763507619085469556
print(1/sqrt(exp(pi)))        # 0.2078795763507619085469556
print([nstr(exp(j*j*(pi/2 + 2*pi*n)), 6) for n in (-1, 0, 1)])   # d'autres valeurs, toutes réelles# ['(111.318 + 0.0j)', '(0.20788 + 0.0j)', '(0.000388203 + 0.0j)']
print(nstr(mpf(537842140)/2587277449 - exp(-pi/2), 3))# 1.87e-20
print(nstr(29/(42 + sqrt(9507)) - exp(-pi/2), 3))# -3.02e-9
print(nstr(abs(log(2)/log(j) - 2*log(2)/(j*pi)), 3))# 0.0
XII·4π par le logarithme complexe (Fagnano)
\(2i\ln\dfrac{1-i}{1+i}\)
=
\(\pi\)

car \(\tfrac{1-i}{1+i}=-i\) et \(\ln(-i)=-i\pi/2\). Même idée, plus directe : \(\pi=-i\ln(-1)\), puisque \(e^{i\pi}=-1\) (XII·1). Formule attribuée à Fagnano, au XVIIIᵉ siècle. Le logarithme complexe a une infinité de valeurs, écartées de \(2\pi i\) ; on prend ici la valeur principale, celle dont la partie imaginaire est entre \(-\pi\) et \(\pi\).

const πtype valeur exactefamille exponentielle complexe
# valeur principale du logarithme complexe, 25 chiffres
from mpmath import mp, j, log, pi
mp.dps = 25
print((1-j)/(1+j))            # (0.0 - 1.0j)
print(2*j*log((1-j)/(1+j)))   # (3.141592653589793238462643 + 0.0j)
print(-j*log(-1))             # (3.141592653589793238462643 + 0.0j)
print(pi)                     # 3.141592653589793238462643
XIII·1le nombre d'or en fraction continue
\(1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{1+\cdots}}}\)
=
\(\dfrac{1+\sqrt5}{2}\)

de \(x^{2}=x+1\), on tire \(x=1+1/x\), et en remplaçant \(x\) par lui-même à l'infini, cette fraction continue faite uniquement de 1. Ses réduites sont les rapports de nombres de Fibonacci : 1, 2, 3/2, 5/3, 8/5, 13/8… Ce sont les plus lentes qui soient, car des 1 partout, c'est le pire cas : \(\varphi\) est le nombre le plus difficile à approcher par des fractions. Avec \(x^{2}+x-1=0\), on obtient de même \(1/\varphi=[0;1,1,1,\dots]\) ; mais l'autre racine, \(-\varphi\), échappe à l'itération \(x\leftarrow1/(1+x)\), qui la repousse et file vers \(1/\varphi\). Quant à \(-1/\varphi\), c'est le « conjugué » de \(\varphi\) au sens de Galois (L·49).

const nombre d'ortype fraction continuefamille fractions continues
# itération, réduites de Fibonacci, puis l'autre racine qui s'échappe
from fractions import Fraction
from mpmath import mp, mpf, sqrt, nstr
mp.dps = 25
x = mpf(1)
for _ in range(60): x = 1 + 1/x                # φ = 1 + 1/φ, itéré
print(x)                      # 1.618033988749894848204587
print((1 + sqrt(5))/2)        # 1.618033988749894848204587
r = [Fraction(1)]
for _ in range(7): r.append(1 + 1/r[-1])
print([str(f) for f in r])                     # rapports de Fibonacci# ['1', '2', '3/2', '5/3', '8/5', '13/8', '21/13', '34/21']
y = mpf('-1.618')                              # on part tout près de −φ…
for _ in range(60): y = 1/(1 + y)
print(nstr(y, 10))                             # … et l'itération file vers 1/φ# 0.6180339887
XIII·2e en fraction continue : un motif parfait
\([2;\,1,2,1,\ 1,4,1,\ 1,6,1,\ 1,8,1,\ \dots]\)
=
\(e\)

la fraction continue de \(e\) n'est pas périodique (\(e\) n'est pas racine d'une équation du second degré, L·48), mais elle suit un motif parfait par triplets \(1,2k,1\), découvert par Euler (1737). Celle de \(\pi\), à l'inverse, semble n'avoir aucun ordre : \([3;7,15,1,292,1,1,1,2,\dots]\). Couper juste avant le grand 292 donne \(355/113\), juste à 7 chiffres ; c'est la fraction de Zu Chongzhi (Vᵉ siècle), le même que pour le volume de la boule (L·10).

const etype fraction continuefamille fractions continues
# les termes de e, le motif qui la reconstruit, puis ceux de π et 355/113
from mpmath import mp, mpf, e, pi, floor, nstr
mp.dps = 60                                    # chiffres de garde pour extraire les termes
def fc(x, n):                                   # les n premiers termes de la fraction continue
    t = []
    for _ in range(n):
        a = int(floor(x)); t.append(a); x = 1/(x - a)
    return t
def valeur(t):                                 # [a0; a1, …, ak] évaluée depuis la fin
    v = mpf(t[-1])
    for a in reversed(t[:-1]): v = a + 1/v
    return v
print(fc(e, 16))              # [2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1]
motif = [2] + [a for k in range(1, 20) for a in (1, 2*k, 1)]
print(nstr(valeur(motif) - e, 3))              # le motif redonne e# 4.76e-59
print(fc(pi, 12))             # [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1]
print(nstr(mpf(355)/113 - pi, 3))# 2.67e-7
XIV·1combien de tirages pour dépasser 1 ?
\(\mathbb E\bigl[\min\{n : U_1+\dots+U_n>1\}\bigr]\)
=
\(e\)

on tire des nombres au hasard entre 0 et 1 et on les additionne jusqu'à dépasser 1 : il en faut en moyenne exactement \(e\). La raison : avoir besoin de plus de \(n\) tirages, c'est que \(U_1+\dots+U_n\leq1\), et la probabilité en vaut \(1/n!\), le volume d'un simplexe (le coin du cube de dimension \(n\)). La moyenne est la somme de ces probabilités, c'est-à-dire la série de \(e\) (XI·1). À ne pas confondre avec \(1+\tfrac12+\dots+\tfrac18=2{,}71786\ldots\), qui ne tombe près de \(e\) que par coïncidence (\(H_8\approx\ln8+\gamma+\tfrac1{16}\)).

const etype sériefamille probabilités
# un million de tirages ; P(N > n) contre 1/n! ; la somme exacte ; puis la coïncidence H₈
import random
from fractions import Fraction
from mpmath import mp, mpf, factorial, nsum, inf, e
random.seed(1)
def tirages():
    total, n = 0.0, 0
    while total <= 1: total += random.random(); n += 1
    return n
T = [tirages() for _ in range(10**6)]
print(sum(T) / len(T))                         # simulation : un million d'essais# 2.718362
print([round(sum(t > n for t in T) / len(T), 4) for n in range(1, 5)])# [1.0, 0.5004, 0.1664, 0.0417]
print([round(1/float(factorial(n)), 4) for n in range(1, 5)])      # P(N > n) = 1/n!# [1.0, 0.5, 0.1667, 0.0417]
mp.dps = 25
print(nsum(lambda n: 1/factorial(n), [0, inf]))# 2.718281828459045235360287
print(e)                      # 2.718281828459045235360287
H8 = sum(Fraction(1, k) for k in range(1, 9))
print(H8, float(e - H8))                       # la coïncidence# 761/280 0.0004246856019023782

LLois

L·1logarithme d'un produit
\(\log_a(MN)\)
=
\(\log_a M+\log_a N\)

pour \(a>0,\ a\neq1\) et \(M,N>0\). Sans cette dernière condition, c'est faux : \(M=N=-1\) donne \(\log_a 1=0\), alors que \(\log_a(-1)\) n'existe pas dans \(\mathbb R\).

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal
from mpmath import mp, mpf, log, nstr
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    a, M, N = base(), pos(), pos()
    err = max(err, abs(log(M*N, a) - (log(M, a) + log(N, a))))
print(nstr(err, 3))       # 6.62e-24
L·2logarithme d'un quotient
\(\log_a\dfrac{M}{N}\)
=
\(\log_a M-\log_a N\)

pour \(a>0,\ a\neq1\) et \(M,N>0\).

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal
from mpmath import mp, mpf, log, nstr
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    a, M, N = base(), pos(), pos()
    err = max(err, abs(log(M/N, a) - (log(M, a) - log(N, a))))
print(nstr(err, 3))       # 3.31e-24
L·3logarithme d'une puissance
\(\log_a M^{q}\)
=
\(q\,\log_a M\)

pour \(a>0,\ a\neq1\), \(M>0\) et \(q\) réel quelconque.

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal
from mpmath import mp, mpf, log, nstr
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    a, M = base(), pos()
    q = mpf(random.uniform(-10, 10))
    err = max(err, abs(log(M**q, a) - q*log(M, a)))
print(nstr(err, 3))       # 2.65e-23
L·4changement de base
\(\log_a N\)
=
\(\dfrac{\log_b N}{\log_b a}\)

pour \(a,b>0\), \(a,b\neq1\) et \(N>0\). C'est elle qui permet de tout calculer avec \(\ln\) seul.

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal
from mpmath import mp, mpf, log, nstr
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    a, b, N = base(), base(), pos()
    err = max(err, abs(log(N, a) - log(N, b)/log(a, b)))
print(nstr(err, 3))       # 6.62e-24
L·5logarithme décimal, dit de Briggs
\(\log_{10} N\)
=
\(\log N\)

pour \(N>0\). C'est une notation : sans base écrite, \(\log\) désigne la base 10 (sur la calculatrice, pas toujours ailleurs).

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal
from mpmath import mp, mpf, log, nstr, log10
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    N = pos()
    err = max(err, abs(log(N, 10) - log10(N)))
print(nstr(err, 3))       # 0
L·6logarithme naturel, ou népérien
\(\log_e N\)
=
\(\ln N\)

pour \(N>0\). Encore une notation, pour la base \(e\).

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal
from mpmath import mp, mpf, log, nstr, e, ln
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    N = pos()
    err = max(err, abs(log(N, e) - ln(N)))
print(nstr(err, 3))       # 1.03e-25
L·7le logarithme défait l'exponentielle
\(\log_a a^{N}\)
=
\(N\)

pour \(a>0,\ a\neq1\) et \(N\) réel quelconque. Avec \(a=e\) : \(\ln e^{N}=N\).

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal
from mpmath import mp, mpf, log, nstr
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    a = base()
    N = mpf(random.uniform(-20, 20))
    err = max(err, abs(log(a**N, a) - N))
print(nstr(err, 3))       # 4.14e-25
L·8l'exponentielle défait le logarithme
\(a^{\log_a N}\)
=
\(N\)

pour \(a>0,\ a\neq1\) et \(N>0\) (ici \(N\) doit être positif, contrairement à L·7). Avec \(a=e\) : \(e^{\ln N}=N\).

sorte loifamille logarithmes
# 1000 tirages au hasard dans le domaine ; on affiche l'écart maximal (relatif)
from mpmath import mp, mpf, log, nstr
import random
mp.dps = 25
random.seed(1)
pos = lambda: mpf(random.uniform(0.01, 100))
base = lambda: random.choice([pos(), mpf(random.uniform(0.01, 0.99))])
err = 0
for _ in range(1000):
    a, N = base(), pos()
    err = max(err, abs(a**log(N, a) - N)/N)
print(nstr(err, 3))       # 6.04e-26
L·9indicatrice d'un carré
\(\varphi(n^{2})\)
=
\(n\,\varphi(n)\)

pour tout entier \(n\geq1\). Plus généralement, \(\varphi(n^{k})=n^{k-1}\varphi(n)\) : élever au carré ne crée aucun nouveau facteur premier.

sorte loifamille indicatrice φ
# vérifiée exhaustivement pour n < 10 000 (la preuve tient en deux lignes)
def phi(n):
    r, m, p = n, n, 2
    while p*p <= m:
        if m % p == 0:
            while m % p == 0: m //= p
            r -= r // p
        p += 1
    return r - r//m if m > 1 else r

print(all(phi(n*n) == n*phi(n) for n in range(1, 10**4)))# True
L·10volume de la boule en dimension n
\(V_n(r)\)
=
\(\dfrac{\pi^{n/2}}{\Gamma\!\left(\frac n2+1\right)}\,r^{n}\)

pour tout entier \(n\geq0\) et \(r>0\). La fonction \(\Gamma\) prolonge la factorielle, avec \(\Gamma(k+1)=k!\) et \(\Gamma(\tfrac12)=\sqrt\pi\) (voir IX·2) : c'est elle qui traite d'un coup les dimensions paires et impaires.

nvolume de la bouleaire de la sphère
1\(2r\)\(2\)
2\(\pi r^{2}\)\(2\pi r\)
3\(\tfrac43\pi r^{3}\)\(4\pi r^{2}\)
4\(\tfrac12\pi^{2} r^{4}\)\(2\pi^{2} r^{3}\)
5\(\tfrac{8}{15}\pi^{2} r^{5}\)\(\tfrac83\pi^{2} r^{4}\)

Une surprise : pour \(r=1\), le volume augmente jusqu'à la dimension 5, puis décroît vers 0. En grande dimension, presque tout le volume se loge contre le bord : une coquille d'épaisseur 1 % en contient \(1-0{,}99^{n}\), soit 5 % en dimension 5 et 63 % en dimension 100. Une orange qui ne serait presque plus que de la peau.

051015205,26
volume de la boule unité, dimension 0 à 20
sorte loifamille boules et sphères
# vérification indépendante par découpage en tranches, pour n = 1 à 10
from mpmath import mp, mpf, pi, gamma, quad, sqrt, nstr
mp.dps = 25
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n
# une boule de dimension n = un empilement de tranches,
# chacune étant une boule de dimension n − 1
err = max(abs(quad(lambda x: V(n-1, sqrt(1-x**2)), [-1, 1]) - V(n))
          for n in range(1, 11))
print(nstr(err, 3))       # 1.03e-25
nmax = max(range(30), key=V)
print(nmax, V(nmax))      # 5 5.263789013914324596711729
L·11aire de la sphère, dérivée du volume
\(S_n(r)=\dfrac{dV_n}{dr}\)
=
\(\dfrac{2\pi^{n/2}}{\Gamma\!\left(\frac n2\right)}\,r^{\,n-1}\)

pour \(n\geq1\) et \(r>0\). La peau, c'est ce qu'on ajoute quand \(r\) grandit d'un cran. Ici \(S_n\) borde la boule de \(\mathbb R^{n}\) ; les mathématiciens la notent souvent \(\mathbb S^{n-1}\), d'après sa propre dimension. L'aire de la sphère unité culmine en dimension 7, à environ 33,07.

sorte loifamille boules et sphères
# dérivée numérique de V comparée à S, 200 tirages (écart relatif)
from mpmath import mp, mpf, pi, gamma, diff, nstr
import random
mp.dps = 25
random.seed(1)
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n
S = lambda n, r=1: 2*pi**(mpf(n)/2) / gamma(mpf(n)/2) * r**(n-1)
err = 0
for _ in range(200):
    n, r = random.randint(1, 12), mpf(random.uniform(0.1, 5))
    err = max(err, abs(diff(lambda t: V(n, t), r) - S(n, r)) / S(n, r))
print(nstr(err, 3))       # 7.5e-26
nmax = max(range(1, 30), key=S)
print(nmax, S(nmax))      # 7 33.07336179231980818717474
L·12récurrence des volumes, de deux en deux
\(V_n(1)\)
=
\(\dfrac{2\pi}{n}\,V_{n-2}(1)\)

pour \(n\geq2\), avec \(V_0=1\) et \(V_1=2\). De quoi tout retrouver sans \(\Gamma\), et voir pourquoi le volume finit par décroître : dès que \(n>2\pi\), le facteur \(2\pi/n\) passe sous 1.

sorte loifamille boules et sphères
# vérifiée pour n = 2 à 59
from mpmath import mp, mpf, pi, gamma, nstr
mp.dps = 25
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n
err = max(abs(V(n) - 2*pi/n * V(n-2)) for n in range(2, 60))
print(nstr(err, 3))       # 5.17e-26
L·13bord de l'hypercube
\(S_n(a)\)
=
\(2n\,a^{n-1}\)

pour un cube de côté \(a\) en dimension \(n\geq1\), de volume \(a^{n}\) : ses \(2n\) faces sont des cubes de dimension \(n-1\). Comme pour la boule (L·11), le bord est la dérivée du volume, à condition de dériver par rapport au rayon de la boule inscrite, \(r=a/2\), car \(V=(2r)^{n}\) (voir L·15). La grande diagonale mesure \(a\sqrt n\) et grandit sans fin.

nvolumebordsommetsarêtes
1\(a\)\(2\)21
2\(a^{2}\)\(4a\)44
3\(a^{3}\)\(6a^{2}\)812
4\(a^{4}\)\(8a^{3}\)1632
5\(a^{5}\)\(10a^{4}\)3280
sorte loifamille hypercubes
# dérivée numérique de V par rapport à r = a/2, 200 tirages (écart relatif)
from mpmath import mp, mpf, diff, nstr
import random
mp.dps = 25
random.seed(1)
V = lambda n, r: (2*r)**n             # r = a/2 : rayon de la boule inscrite
S = lambda n, a: 2*n*a**(n-1)
err = 0
for _ in range(200):
    n, a = random.randint(1, 12), mpf(random.uniform(0.1, 5))
    err = max(err, abs(diff(lambda r: V(n, r), a/2) - S(n, a)) / S(n, a))
print(nstr(err, 3))       # 2.53e-26
L·14faces de l'hypercube
\(f_k(n)\)
=
\(2^{\,n-k}\dbinom{n}{k}\)

nombre de faces de dimension \(k\) du cube de dimension \(n\) : une face fixe \(n-k\) coordonnées, chacune à 0 ou à 1, et laisse les \(k\) autres libres. Pour le tesseract : 16 sommets, 32 arêtes, 24 carrés, 8 cubes. En comptant tout, cube compris, \(\sum_k f_k(n)=3^{n}\) : chaque coordonnée a trois états.

sorte loifamille hypercubes
# énumération exhaustive de toutes les faces, n = 1 à 8 (la dernière ligne montre n = 8)
from itertools import product
from math import comb
ok = True
for n in range(1, 9):
    f = [0]*(n+1)
    for face in product('01*', repeat=n):   # 0, 1 : fixée ; * : libre
        f[face.count('*')] += 1
    ok &= all(f[k] == 2**(n-k)*comb(n, k) for k in range(n+1))
    ok &= sum(f) == 3**n
print(ok)                 # True
print(f)                  # [256, 1024, 1792, 1792, 1120, 448, 112, 16, 1]
L·15volume et bord des solides circonscrits
\(V\)
=
\(\dfrac{r\,S}{n}\)

pour tout solide de \(\mathbb R^{n}\) dont chaque face touche une même sphère de rayon \(r\), et pour la boule elle-même : on le découpe en pyramides de sommet le centre et de hauteur \(r\), chacune de volume \(r\times\text{base}/n\). Comme \(V\) est proportionnel à \(r^{n}\), cela revient à \(S=dV/dr\), ce qui explique à la fois L·11 et L·13.

sorte loifamille boules et sphères ; hypercubes
# trois familles de solides (boule, cube, hyperoctaèdre), n = 1 à 12
from mpmath import mp, mpf, pi, gamma, sqrt, factorial, nstr
mp.dps = 25
err = 0
for n in range(1, 13):
    # boule de rayon 1
    V, S, r = pi**(mpf(n)/2)/gamma(mpf(n)/2+1), 2*pi**(mpf(n)/2)/gamma(mpf(n)/2), 1
    err = max(err, abs(V - r*S/n)/V)
    # cube de côté 2, boule inscrite de rayon 1
    V, S, r = mpf(2)**n, 2*n*mpf(2)**(n-1), 1
    err = max(err, abs(V - r*S/n)/V)
    # hyperoctaèdre |x1|+…+|xn| ≤ 1 : 2ⁿ facettes, rayon inscrit 1/√n
    V, S, r = mpf(2)**n/factorial(n), mpf(2)**n*sqrt(n)/factorial(n-1), 1/sqrt(n)
    err = max(err, abs(V - r*S/n)/V)
print(nstr(err, 3))       # 2.47e-26
L·16des boules dans les coins
\(\rho_n\)
=
\(\sqrt{n}-1\)

dans le cube \([-2,2]^{n}\), on place \(2^{n}\) boules de rayon 1 centrées en \((\pm1,\dots,\pm1)\), et \(\rho_n\) est le rayon de la plus grande boule centrale qui tient entre elles. Dimension 2 : \(\rho\approx0{,}41\). Dimension 4 : \(\rho=1\), aussi grosse que les autres. Dimension 9 : \(\rho=2\), elle touche les faces du cube. Dès la dimension 10, elle en dépasse, alors que toutes les boules des coins restent dedans. En grande dimension, le cube ressemble moins à une boîte qu'à un oursin.

sorte loifamille boules et sphères ; hypercubes
# rayon de la boule centrale ; au-delà de 2, elle sort du cube
from math import sqrt
# centre → centre d'une boule de coin : √n ; on retire son rayon 1
rho = {n: sqrt(n) - 1 for n in range(1, 21)}
print(rho[4])             # 1.0
print(rho[9])             # 2.0
print(min(n for n in rho if rho[n] > 2))# 10
L·17Γ aux demi-entiers
\(\Gamma\!\left(n+\tfrac12\right)\)
=
\(\dfrac{(2n)!}{4^{n}\,n!}\,\sqrt{\pi}\)

pour tout entier \(n\geq0\) ; \(n=0\) redonne IX·2. C'est par là que \(\sqrt\pi\) entre dans le volume des boules de dimension impaire, et seulement dans celles-là (L·10).

sorte loifamille fonction Γ
# n = 0 à 39, écart relatif
from mpmath import mp, mpf, gamma, factorial, sqrt, pi, nstr
mp.dps = 25
err = max(abs(gamma(n + mpf(1)/2) - factorial(2*n)/(4**n*factorial(n))*sqrt(pi))
          / gamma(n + mpf(1)/2) for n in range(0, 40))
print(nstr(err, 3))         # 2.28e-26
L·18duplication de Legendre
\(\Gamma(s)\,\Gamma\!\left(s+\tfrac12\right)\)
=
\(2^{\,1-2s}\sqrt{\pi}\;\Gamma(2s)\)

pour tout \(s\) hors des pôles \(0,-\tfrac12,-1,\dots\), complexe compris. C'est la loi des demi-pas : elle soude les valeurs de \(\Gamma\) décalées de \(\tfrac12\), donc les dimensions paires et impaires, et c'est d'elle que vient le \(-\tfrac12\) du pic des boules (A121546).

sorte loifamille fonction Γ
# 200 points complexes tirés au hasard, écart relatif
from mpmath import mp, mpf, mpc, gamma, sqrt, pi, nstr
import random
mp.dps = 25
random.seed(1)
err = 0
for _ in range(200):
    s = mpc(random.uniform(0.05, 8), random.uniform(-5, 5))
    l = gamma(s)*gamma(s + mpf(1)/2)
    err = max(err, abs(l - 2**(1-2*s)*sqrt(pi)*gamma(2*s))/abs(l))
print(nstr(err, 3))         # 4.55e-26
L·19réflexion d'Euler
\(\Gamma(s)\,\Gamma(1-s)\)
=
\(\dfrac{\pi}{\sin(\pi s)}\)

pour tout \(s\) non entier, complexe compris. En \(s=\tfrac12\) : \(\Gamma(\tfrac12)^{2}=\pi\), c'est-à-dire IX·2.

sorte loifamille fonction Γ
# 200 points complexes tirés au hasard, écart relatif
from mpmath import mp, mpc, gamma, sin, pi, nstr
import random
mp.dps = 25
random.seed(1)
err = 0
for _ in range(200):
    s = mpc(random.uniform(-6, 6), random.uniform(-3, 3))
    l = gamma(s)*gamma(1-s)
    err = max(err, abs(l - pi/sin(pi*s))/abs(l))
print(nstr(err, 3))         # 3.16e-25
L·20équation fonctionnelle de Riemann, forme « sphère »
\(\dfrac{\zeta(s)}{S(s)}\)
=
\(\dfrac{\zeta(1-s)}{S(1-s)}\)

où \(S(s)=\dfrac{2\pi^{s/2}}{\Gamma(s/2)}\) est l'aire de la sphère unité qui borde la boule de dimension \(s\) (L·11), une dimension désormais complexe. C'est l'équation de Riemann (1859), \(\xi(s)=\xi(1-s)\) avec \(\xi(s)=\tfrac12 s(s-1)\,\pi^{-s/2}\Gamma(s/2)\,\zeta(s)\), réécrite : ζ divisée par l'aire de la sphère est symétrique autour de \(\tfrac12\). Exemple : la sphère de dimension −1 a une « aire » de \(-1/\pi\), et Bâle, \(\zeta(2)=\pi^{2}/6\), donne aussitôt \(\zeta(-1)=-\tfrac1{12}\).

sources

B. Riemann, « Ueber die Anzahl der Primzahlen unter einer gegebenen Grösse », Monatsberichte der Berliner Akademie, 1859 : l'équation fonctionnelle, sous la forme en \(\xi\).

J. Tate, Fourier analysis in number fields and Hecke's zeta-functions, thèse, Princeton, 1950 ; publiée dans J. W. S. Cassels et A. Fröhlich (éd.), Algebraic Number Theory, Academic Press, 1967. Le facteur \(\pi^{-s/2}\Gamma(s/2)\) y devient le facteur local de ζ à la place réelle : l'intégrale de la gaussienne \(e^{-\pi x^{2}}\) contre \(|x|^{s}\), la même gaussienne qui donne l'aire des sphères.

A. Karlsson et M. Pallich, « Volumes of spheres and special values of zeta functions of ℤ and ℤ/nℤ », 2022, arXiv:2209.03590. Lecture voisine mais différente : l'aire de la sphère unité de chaque dimension y est un produit de valeurs spéciales d'une autre fonction zêta, celle de ℤ, qui a elle aussi une symétrie \(s\leftrightarrow1-s\).

À notre connaissance, la réécriture \(\zeta(s)/S(s)=\zeta(1-s)/S(1-s)\) et le calcul de \(\zeta(-1)\) par la « sphère de dimension −1 » ne figurent tels quels dans aucune de ces sources ; ils en découlent en une ligne. À ne pas confondre avec la sphère de Riemann, qui désigne tout autre chose : le plan complexe complété par un point à l'infini.

sorte loifamille fonction Γ ; valeurs de ζ ; boules et sphères
# 200 points complexes tirés au hasard, puis ζ(−1) retrouvé depuis Bâle
from mpmath import mp, mpc, zeta, gamma, pi, nstr
import random
mp.dps = 25
random.seed(1)
S = lambda s: 2*pi**(s/2)/gamma(s/2)     # aire de la sphère, L·11
err = 0
for _ in range(200):
    s = mpc(random.uniform(-8, 9), random.uniform(-20, 20))
    l = zeta(s)/S(s)
    err = max(err, abs(l - zeta(1-s)/S(1-s))/abs(l))
print(nstr(err, 3))         # 1.37e-25
print(S(-1))                # -0.3183098861837906715377675
print(zeta(2)/S(2) * S(-1)) # -0.08333333333333333333333333
L·21l'empilement de E8, le plus dense en dimension 8cité · Viazovska 2016
\(\Delta_8\)
=
\(\dfrac{\pi^{4}}{384}\)

densité maximale d'un empilement de boules égales en dimension 8, atteinte par le réseau \(E_8\) : les points de \(\mathbb R^{8}\) à coordonnées toutes entières ou toutes demi-entières, de somme paire. Ses 240 vecteurs les plus courts sont les « racines » de \(E_8\) ; chaque boule en touche donc 240 autres, et ces 240 points sont les sommets d'un solide de dimension 8, le polytope de Gosset \(4_{21}\). Ses symétries forment un groupe fini de 696 729 600 éléments ; le groupe de Lie \(E_8\), lui, est de dimension 248. La densité vaut \(V_8(1/\sqrt2)\), un simple volume de L·10. Que personne ne puisse faire mieux, c'est le théorème de Viazovska : Idem le cite, le code en vérifie les ingrédients.

sources

M. Viazovska, « The sphere packing problem in dimension 8 », Annals of Mathematics 185 (2017), arXiv:1603.04246. Médaille Fields 2022.

sorte loifamille empilements ; boules et sphères
# construction du réseau, comptage des voisines, covolume et densité
from itertools import product
from mpmath import mp, mpf, pi, gamma, sqrt, matrix, det
mp.dps = 25
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n    # L·10
# coordonnées doublées w = 2v : toutes paires ou toutes impaires, Σw ≡ 0 mod 4
in_e8 = lambda w: (all(x % 2 == 0 for x in w) or all(x % 2 for x in w)) and sum(w) % 4 == 0
racines = [w for w in product(range(-2, 3), repeat=8)
           if sum(x*x for x in w) == 8 and in_e8(w)]     # |v|² = 2
print(len(racines))           # 240
B = matrix([[2,0,0,0,0,0,0,0], [-1,1,0,0,0,0,0,0], [0,-1,1,0,0,0,0,0],
            [0,0,-1,1,0,0,0,0], [0,0,0,-1,1,0,0,0], [0,0,0,0,-1,1,0,0],
            [0,0,0,0,0,-1,1,0], [mpf(1)/2]*8])           # une base de E8
print(abs(det(B)))            # 1.0
print(V(8, 1/sqrt(2)) / abs(det(B)))# 0.2536695079010480136365634
print(pi**4/384)              # 0.2536695079010480136365634
L·22les couches du réseau E8
\(\#\{v\in E_8 : |v|^{2}=2n\}\)
=
\(240\,\sigma_3(n)\)

pour tout \(n\geq1\), où \(\sigma_3(n)\) est la somme des cubes des diviseurs de \(n\) : 240 points à distance \(\sqrt2\), puis 2 160, 6 720, 17 520… La raison est profonde : la série qui compte ces points (la série thêta de \(E_8\)) est une forme modulaire, la série d'Eisenstein \(E_4\). Ce sont ces mêmes formes modulaires qui portent la preuve de Viazovska (L·21).

sources

J.-P. Serre, Cours d'arithmétique, PUF, 1970, chap. VII : séries thêta et formes modulaires, dont celle de \(E_8\).

sorte loifamille empilements
# dénombrement exact des points du réseau, couche par couche, n = 1 à 5
from collections import Counter
def compte(valeurs, qmax):                    # w = 2v ; état (Σw², Σw mod 4)
    etats = Counter({(0, 0): 1})
    for _ in range(8):
        nouv = Counter()
        for (q, s), c in etats.items():
            for w in valeurs:
                if q + w*w <= qmax:
                    nouv[(q + w*w, (s + w) % 4)] += c
        etats = nouv
    return etats
N = 5
entiers = compte(range(-8, 9, 2), 8*N)       # v entier
demi    = compte(range(-9, 10, 2), 8*N)      # v demi-entier
sigma3 = lambda n: sum(d**3 for d in range(1, n+1) if n % d == 0)
print([entiers[(8*n, 0)] + demi[(8*n, 0)] for n in range(1, N+1)])# [240, 2160, 6720, 17520, 30240]
print([240*sigma3(n) for n in range(1, N+1)])# [240, 2160, 6720, 17520, 30240]
L·23le réseau de Leech, le plus dense en dimension 24cité · Cohn et al. 2016
\(\Delta_{24}\)
=
\(\dfrac{\pi^{12}}{12!}\)

densité maximale en dimension 24, atteinte par le réseau de Leech : covolume 1, aucun vecteur de longueur \(\sqrt2\), et 196 560 vecteurs de longueur 2, donc 196 560 voisines pour chaque boule de rayon 1. La densité est alors exactement \(V_{24}(1)=\pi^{12}/12!\). Le code tire ces nombres de la série thêta de Leech, \(\theta=E_{12}-\tfrac{65520}{691}\Delta\), identité de formes modulaires que l'on cite ; l'optimalité est un théorème de 2016, cité lui aussi.

sources

H. Cohn, A. Kumar, S. D. Miller, D. Radchenko, M. Viazovska, « The sphere packing problem in dimension 24 », Annals of Mathematics 185 (2017), arXiv:1603.06518.

sorte loifamille empilements ; boules et sphères
# nombre de vecteurs de norme² 2, 4, 6 via la série thêta, puis densité
from fractions import Fraction
from mpmath import mp, mpf, pi, gamma, factorial
mp.dps = 25
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n    # L·10
N = 3
P = [1] + [0]*N                               # ∏ (1 − qⁿ)²⁴, jusqu'à q^N
for n in range(1, N+1):
    for _ in range(24):
        for k in range(N, n-1, -1):
            P[k] -= P[k-n]
tau = [0] + P[:N]                             # Δ = q·∏ : τ(1), τ(2), τ(3)
sigma11 = lambda n: sum(d**11 for d in range(1, n+1) if n % d == 0)
c = Fraction(65520, 691)
print([int(c*(sigma11(n) - tau[n])) for n in range(1, N+1)])# [0, 196560, 16773120]
print(V(24))                  # 0.001929574309403923047903346
print(pi**12/factorial(12))   # 0.001929574309403923047903346
L·24l'ADN triangulaire du comptage
\(T(n,k)\)
=
\(T(n-1,k-1)+w(n,k)\,T(n-1,k)\)

avec \(T(0,0)=1\). Le même moule, un seul poids qui change : où placer le \(n\)-ième objet ? Soit il ouvre un groupe à lui seul (premier terme), soit il rejoint l'existant, et le poids compte de combien de façons : \(k\) groupes où entrer, \(n-1\) places dans les cycles, \(n+k-1\) places dans les files. Le code ne fait pas confiance à la récurrence : il énumère réellement les objets jusqu'à \(n=6\).

trianglepoids \(w(n,k)\)comptesomme des lignes
Pascal\(1\)sous-ensembles de taille \(k\)\(2^{n}\)
Stirling 2ᵉ\(k\)répartitions en \(k\) groupesBell
Stirling 1ʳᵉ\(n-1\)permutations à \(k\) cycles\(n!\)
Lah\(n+k-1\)répartitions en \(k\) files1, 3, 13, 73, 501…
sorte loifamille comptage
# énumération réelle des sous-ensembles, partitions, permutations et files, n = 0 à 6
def partitions(elems):                        # toutes les partitions d'un ensemble
    if not elems:
        yield []
        return
    x, reste = elems[0], elems[1:]
    for p in partitions(reste):
        yield [[x]] + p                           # x seul dans un bloc
        for i in range(len(p)):                   # ou x rejoint un bloc
            yield p[:i] + [[x] + p[i]] + p[i+1:]
from itertools import combinations, permutations, product
from math import factorial
def triangle(w, N):
    T = [[1]]
    for n in range(1, N+1):
        prev = T[-1] + [0]
        T.append([(prev[k-1] if k else 0) + w(n, k)*prev[k] for k in range(n+1)])
    return T
def cycles(p):                                    # nombre de cycles d'une permutation
    vu, c = set(), 0
    for i in range(len(p)):
        if i not in vu:
            c += 1
            while i not in vu: vu.add(i); i = p[i]
    return c
def compte(n, famille):
    t = [0]*(n+1)
    if famille == 'pascal':
        for k in range(n+1): t[k] = sum(1 for _ in combinations(range(n), k))
    if famille == 'stirling2':
        for P in partitions(list(range(n))): t[len(P)] += 1
    if famille == 'stirling1':
        for p in permutations(range(n)): t[cycles(p)] += 1
    if famille == 'lah':                          # chaque groupe mis en file
        for P in partitions(list(range(n))):
            t[len(P)] += sum(1 for _ in product(*[permutations(b) for b in P]))
    return t
poids = {'pascal': lambda n, k: 1, 'stirling2': lambda n, k: k,
         'stirling1': lambda n, k: n-1, 'lah': lambda n, k: n+k-1}
print(all(compte(n, f) == triangle(w, 6)[n] for f, w in poids.items() for n in range(7)))# True
print({f: sum(triangle(w, 6)[6]) for f, w in poids.items()})# {'pascal': 64, 'stirling2': 203, 'stirling1': 720, 'lah': 4051}
L·25Bernoulli et ζ aux entiers pairs (Euler)
\(\zeta(2k)\)
=
\((-1)^{k+1}\,\dfrac{B_{2k}\,(2\pi)^{2k}}{2\,(2k)!}\)

pour tout entier \(k\geq1\). Les nombres de Bernoulli \(B_{2k}\) (1/6, −1/30, 1/42…) sont les coefficients des sommes de puissances \(1^{p}+2^{p}+\dots+n^{p}\) (Faulhaber) : c'est le fil « sommes de puissances → π ». \(k=1\) donne Bâle (II·1), \(k=2\) donne \(\pi^{4}/90\) (II·2). Côté négatif, \(\zeta(1-2k)=-B_{2k}/2k\) : c'est le \(-1/12\) de L·20. Pour \(\zeta(3),\zeta(5)\dots\), aucune formule de ce genre n'est connue.

sorte loifamille comptage ; valeurs de ζ
# k = 1 à 15, écart relatif ; puis B₂, B₄, B₆ en fractions
from mpmath import mp, zeta, bernoulli, bernfrac, pi, factorial, nstr
mp.dps = 25
err = max(abs(zeta(2*k) - (-1)**(k+1)*bernoulli(2*k)*(2*pi)**(2*k)/(2*factorial(2*k)))
          / zeta(2*k) for k in range(1, 16))
print(nstr(err, 3))           # 1.81e-25
print([bernfrac(2*k) for k in (1, 2, 3)])# [(1, 6), (-1, 30), (1, 42)]
L·26nombres d'Euler et β aux entiers impairs
\(\beta(2k+1)\)
=
\((-1)^{k}\,\dfrac{E_{2k}\,\pi^{2k+1}}{4^{k+1}\,(2k)!}\)

pour tout entier \(k\geq0\), où \(\beta\) est la fonction de Dirichlet de III·1. Les \(|E_{2k}|\) (1, 1, 5, 61, 1385…) comptent les permutations en zigzag, qui montent et descendent en alternance. \(k=0\) donne Leibniz (I·2), \(k=1\) donne \(\pi^{3}/32\) (III·2). C'est le miroir exact de L·25 : pour β, ce sont les valeurs paires qui résistent, à commencer par \(\beta(2)=G\), la constante de Catalan.

sorte loifamille comptage ; β de Dirichlet
# k = 0 à 9, écart relatif ; puis les premiers nombres d'Euler
from mpmath import mp, mpf, nsum, inf, eulernum, pi, factorial, nstr
mp.dps = 25
beta = lambda s: nsum(lambda j: mpf(-1)**j/(2*j+1)**s, [0, inf])
err = max(abs(beta(2*k+1) - (-1)**k*eulernum(2*k)*pi**(2*k+1)/(4**(k+1)*factorial(2*k)))
          / beta(2*k+1) for k in range(0, 10))
print(nstr(err, 3))           # 1.29e-25
print([int(eulernum(2*k)) for k in range(6)])# [1, -1, 5, -61, 1385, -50521]
L·27intégrales de Wallis
\(W_n\,W_{n-1}\)
=
\(\dfrac{\pi}{2n}\)

pour \(n\geq1\), où \(W_n=\int_0^{\pi/2}\sin^{n}x\,dx\). En pair et impair : \(W_{2m}=\tfrac{\pi}{2}\binom{2m}{m}4^{-m}\) contient π, \(W_{2m+1}=4^{m}\big/\big((2m+1)\binom{2m}{m}\big)\) n'en contient pas. C'est le fil caché de plusieurs fiches : couper une boule en tranches (Zu, L·10) donne \(V_n=2W_nV_{n-1}\), et deux crans d'un coup donnent la récurrence \(V_n=\tfrac{2\pi}{n}V_{n-2}\) de L·12 ; le rapport \(W_{2m}/W_{2m+1}\to1\) donne le produit de Wallis (IV·1) ; les Steinmetz de dimension \(n\) en sont des multiples, d'où « rationnel en dimension impaire, π en dimension paire » ; et le binomial central de X·3 y apparaît.

sorte loifamille boules et sphères ; comptage
# n = 1 à 20 : le produit, le lien avec les boules, puis les deux formes closes
from mpmath import mp, mpf, quad, sin, pi, gamma, binomial, nstr
mp.dps = 25
W = lambda n: quad(lambda x: sin(x)**n, [0, pi/2])
V = lambda n: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1)          # L·10
print(nstr(max(abs(W(n)*W(n-1) - pi/(2*n)) for n in range(1, 21)), 3))# 6.46e-27
print(nstr(max(abs(V(n) - 2*W(n)*V(n-1)) for n in range(1, 21)), 3))# 1.03e-25
print(nstr(max(abs(W(2*m) - pi/2*binomial(2*m, m)/4**m) for m in range(10)), 3))# 6.46e-27
print(nstr(max(abs(W(2*m+1) - 4**m/((2*m+1)*binomial(2*m, m))) for m in range(10)), 3))# 1.29e-26
L·28série de l'antilogarithme (Maclaurin)
\(b^{x}\)
=
\(\displaystyle\sum_{k=0}^{\infty}\frac{(x\ln b)^{k}}{k!}\)

pour \(b>0\) et \(x\) réel : c'est le développement de Maclaurin de l'exponentielle, puisque \(b^{x}=e^{x\ln b}\). Les anciens manuels l'appellent « formule de Mac-Laurin » et l'écrivent avec « log b » : ce log doit être le logarithme naturel. Avec le log décimal (L·5), \(b=10\), \(x=1\) donnerait \(e\) au lieu de 10. Les factorielles écrasent vite les termes, d'autant plus que \(x\ln b\) est petit : d'où l'intérêt de se ramener d'abord à un petit exposant. Avec \(b=e\), \(x=1\), on obtient XI·1.

sorte loifamille logarithmes
# 200 tirages au hasard ; nombre de termes selon la taille de x·ln b ; puis le piège du log décimal
from mpmath import mp, mpf, ln, log10, factorial, nstr
import random
mp.dps = 35          # chiffres de garde : si x·ln b < 0, les termes alternent et se compensent
random.seed(1)
def antilog(b, x, N=200):
    t = s = mpf(1)
    for k in range(1, N):
        t *= x*ln(b)/k
        s += t
    return s
err = 0
for _ in range(200):
    b, x = mpf(random.uniform(0.1, 10)), mpf(random.uniform(-5, 5))
    err = max(err, abs(antilog(b, x) - b**x) / b**x)
print(nstr(err, 3))           # 3.36e-28
def termes(u):                                 # termes nécessaires pour 25 chiffres
    t, k = mpf(1), 0
    while abs(t) > mpf(10)**-25:
        k += 1
        t *= u/k
    return k
print(termes(mpf('0.1')), termes(mpf(10)))# 15 64
print(nstr(sum(log10(10)**k/factorial(k) for k in range(60)), 12))# 2.71828182846
L·29somme de φ sur les diviseurs (Gauss)
\(\sum_{d\mid n}\varphi(d)\)
=
\(n\)

pour tout entier \(n\geq1\). Une preuve en une image : on écrit les \(n\) fractions \(\tfrac1n,\tfrac2n,\dots,\tfrac nn\) et on les simplifie ; chacune prend un dénominateur \(d\) qui divise \(n\), et il y en a exactement \(\varphi(d)\) pour chaque \(d\). Pour \(n=6\) : 1 + 1 + 2 + 2 = 6. Avec L·30, elle donne \(\sum_{d\mid n}\Lambda(d)=\ln\bigl(\sum_{d\mid n}\varphi(d)\bigr)\), les deux côtés valant \(\ln n\).

sorte loifamille nombres premiers ; indicatrice φ
# vérifiée exactement pour n = 1 à 3000 ; puis le détail pour n = 6
def facteurs(n):                                 # {premier: exposant}
    f, p = {}, 2
    while p*p <= n:
        while n % p == 0:
            f[p] = f.get(p, 0) + 1
            n //= p
        p += 1
    if n > 1: f[n] = f.get(n, 0) + 1
    return f
diviseurs = lambda n: [d for d in range(1, n+1) if n % d == 0]
def phi(n):
    r = n
    for p in facteurs(n): r -= r // p
    return r
print(all(sum(phi(d) for d in diviseurs(n)) == n for n in range(1, 3001)))# True
print([phi(d) for d in diviseurs(6)])# [1, 1, 2, 2]
L·30la fonction de von Mangoldt
\(\sum_{d\mid n}\Lambda(d)\)
=
\(\ln n\)

pour tout entier \(n\geq1\), où \(\Lambda(d)=\ln p\) si \(d\) est une puissance d'un nombre premier \(p\), et 0 sinon. Chaque premier « pèse » son logarithme : si \(p^{a}\) divise exactement \(n\), les diviseurs \(p,p^{2},\dots,p^{a}\) apportent \(a\ln p\), et la somme sur tous les premiers redonne \(\ln n\). Combinée à L·29, elle s'écrit \(\sum_{d\mid n}\Lambda(d)=\ln\bigl(\sum_{d\mid n}\varphi(d)\bigr)\). \(\Lambda\) est aussi la fonction dont \(-\zeta'/\zeta\) fait la somme : \(\sum\Lambda(n)/n^{s}=-\zeta'(s)/\zeta(s)\).

sorte loifamille nombres premiers
# n = 2 à 2000 : la loi, puis la forme combinée avec L·29
def facteurs(n):                                 # {premier: exposant}
    f, p = {}, 2
    while p*p <= n:
        while n % p == 0:
            f[p] = f.get(p, 0) + 1
            n //= p
        p += 1
    if n > 1: f[n] = f.get(n, 0) + 1
    return f
diviseurs = lambda n: [d for d in range(1, n+1) if n % d == 0]
def phi(n):
    r = n
    for p in facteurs(n): r -= r // p
    return r
from mpmath import mp, log, fsum, nstr
mp.dps = 25
def Lambda(d):
    f = facteurs(d)
    return log(list(f)[0]) if len(f) == 1 else 0
print(nstr(max(abs(fsum(Lambda(d) for d in diviseurs(n)) - log(n)) for n in range(2, 2001)), 3))# 1.03e-25
print(nstr(max(abs(fsum(Lambda(d) for d in diviseurs(n))# 1.03e-25
                   - log(sum(phi(d) for d in diviseurs(n)))) for n in range(2, 2001)), 3))
L·31l'exponentielle intégrale et γ
\(\operatorname{Ei}(x)\)
=
\(\gamma+\ln x+\sum_{k=1}^{\infty}\frac{x^{k}}{k\cdot k!}\)

pour \(x>0\), où \(\operatorname{Ei}(x)=\int_{-\infty}^{x}\frac{e^{t}}{t}\,dt\) (en valeur principale). La constante d'Euler de XI·2 y apparaît d'elle-même : quand \(x\to0\), \(\operatorname{Ei}(x)-\ln x\) tend vers \(\gamma\). Les factorielles au dénominateur font converger la série aussi vite que celle de \(e\) (XI·1).

sorte loifamille nombres premiers ; logarithmes
# 200 tirages au hasard (écart relatif) ; puis γ retrouvé quand x → 0
from mpmath import mp, mpf, ei, log, euler, nsum, factorial, inf, nstr
import random
mp.dps = 25
random.seed(1)
serie = lambda x: euler + log(x) + nsum(lambda k: x**k/(k*factorial(k)), [1, inf])
err = 0
for _ in range(200):
    x = mpf(random.uniform(0.01, 30))
    err = max(err, abs(ei(x) - serie(x)) / abs(ei(x)))
print(nstr(err, 3))           # 2.55e-26
x = mpf(10)**-12                              # l'écart restant avec γ vaut environ x
print(ei(x) - log(x))         # 0.5772156649025328606065122
print(euler)                  # 0.5772156649015328606065121
L·32le logarithme intégral
\(\operatorname{li}(x)\)
=
\(\operatorname{Ei}(\ln x)\)

pour \(x>1\), où \(\operatorname{li}(x)=\int_0^{x}\frac{dt}{\ln t}\) (en valeur principale). Avec L·30, pour tout entier \(n\geq2\) : \(\operatorname{li}(n)=\operatorname{Ei}\bigl(\sum_{d\mid n}\Lambda(d)\bigr)\) ; attention, c'est bien \(n\), un entier, des deux côtés. Le logarithme intégral est la meilleure approximation simple du nombre \(\pi(x)\) de nombres premiers jusqu'à \(x\) : Gauss l'avait deviné, et c'est le théorème des nombres premiers (Hadamard et de la Vallée Poussin, 1896). Jusqu'à des hauteurs immenses, li(x) dépasse \(\pi(x)\), mais Littlewood a montré en 1914 que l'ordre s'inverse une infinité de fois.

sorte loifamille nombres premiers ; logarithmes
# 200 tirages ; la forme li(n) = Ei(Σ Λ(d)) pour n = 2 à 500 ; puis π(10⁶) face à li(10⁶)
def facteurs(n):                                 # {premier: exposant}
    f, p = {}, 2
    while p*p <= n:
        while n % p == 0:
            f[p] = f.get(p, 0) + 1
            n //= p
        p += 1
    if n > 1: f[n] = f.get(n, 0) + 1
    return f
diviseurs = lambda n: [d for d in range(1, n+1) if n % d == 0]
def phi(n):
    r = n
    for p in facteurs(n): r -= r // p
    return r
from mpmath import mp, mpf, li, ei, log, fsum, nstr
import random
mp.dps = 25
random.seed(1)
err = max(abs(li(x) - ei(log(x))) / li(x)
          for x in (mpf(random.uniform(1.5, 1e6)) for _ in range(200)))
print(nstr(err, 3))           # 9.98e-26
def Lambda(d):
    f = facteurs(d)
    return log(list(f)[0]) if len(f) == 1 else 0
print(nstr(max(abs(li(n) - ei(fsum(Lambda(d) for d in diviseurs(n)))) for n in range(2, 501)), 3))# 8.27e-24
N = 10**6                                        # comptage des premiers par crible
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for p in range(2, int(N**0.5)+1):
    if crible[p]: crible[p*p::p] = bytearray(len(crible[p*p::p]))
print(sum(crible))            # 78498
print(nstr(li(N), 8))         # 78627.549
L·33la formule d'Euler
\(e^{ix}\)
=
\(\cos x+i\sin x\)

pour tout réel \(x\) (et même tout complexe). Avec \(x=\pi\), c'est XII·1. En l'élevant à la puissance \(m\), on obtient la formule de Moivre, \((\cos x+i\sin x)^{m}=\cos mx+i\sin mx\) : \(e^{4ik\pi/n}\) est le carré de \(e^{2ik\pi/n}\). Avec \(x=\pi/4\), on trouve une racine carrée de \(i\) : \(e^{i\pi/4}=\tfrac{\sqrt2}{2}+i\,\tfrac{\sqrt2}{2}\), dont le carré vaut bien \(e^{i\pi/2}=i\).

sorte loifamille exponentielle complexe
# 200 tirages : Euler et Moivre ; puis la racine carrée de i
from mpmath import mp, mpf, exp, cos, sin, pi, j, sqrt, nstr
import random
mp.dps = 25
random.seed(1)
err = 0
for _ in range(200):
    x, m = mpf(random.uniform(-50, 50)), random.randint(-9, 9)
    err = max(err, abs(exp(j*x) - (cos(x) + j*sin(x))),
                   abs((cos(x) + j*sin(x))**m - (cos(m*x) + j*sin(m*x))))
print(nstr(err, 3))           # 7.78e-26
r = sqrt(2)/2 + j*sqrt(2)/2
print(nstr(abs(exp(j*pi/4) - r), 3), nstr(r**2, 5))# 1.29e-26 (0.0 + 1.0j)
L·34les racines de l'unité se compensent
\(\sum_{k=0}^{n-1}e^{2ik\pi/n}\)
=
\(0\)

pour tout entier \(n\geq2\). Les \(n\) nombres \(e^{2ik\pi/n}\) sont les sommets d'un polygone régulier inscrit dans le cercle unité ; leur centre de gravité est le centre du cercle, donc leur somme est nulle. Leur produit vaut \((-1)^{n+1}\). Pour \(n=2\), c'est \(1+e^{i\pi}=0\), l'identité d'Euler (XII·1) elle-même.

sorte loifamille exponentielle complexe
# n = 2 à 60 : la somme, puis le produit
from mpmath import mp, exp, pi, j, fsum, fprod, nstr
mp.dps = 25
racines = lambda n: [exp(2*j*k*pi/n) for k in range(n)]
print(nstr(max(abs(fsum(racines(n))) for n in range(2, 61)), 3))# 4.12e-25
print(nstr(max(abs(fprod(racines(n)) - (-1)**(n+1)) for n in range(1, 61)), 3))# 1.18e-24
L·352 et 2 font 4, à tous les étages
\(2+2=2\times2=2^{2}=2\uparrow\uparrow2=\cdots\)
=
\(4\)

chaque opération répète la précédente : la multiplication répète l'addition, la puissance répète la multiplication, la « tour » \(2\uparrow\uparrow2=2^{2}\) répète la puissance, et ainsi de suite sans fin. Appliquée à 2 et 2, chaque étage répète deux fois 2 à l'étage du dessous, et retombe donc sur 4. Aucun autre nombre ne fait ça : 3 donne 6, 9, 27, puis 7 625 597 484 987. Le seul \(x\) non nul tel que \(x+x=x\times x\) est 2. Côté logarithmes : \(\log_b a+\log_b a=\log_b a\times\log_b a\) exactement quand \(\log_b a\) vaut 0 ou 2, c'est-à-dire \(a=1\) ou \(a=b^{2}\).

sorte loifamille opérations
# 2 ∘ 2 sur huit étages, 3 ∘ 3 sur quatre, puis les solutions de x + x = x × x
def hyper(n, a, b):             # étage n : 1 = +, 2 = ×, 3 = puissance, 4 = tour…
    if n == 1: return a + b
    if n == 2: return a * b
    if n == 3: return a ** b
    if b == 1: return a
    return hyper(n-1, a, hyper(n, a, b-1))   # l'étage n répète l'étage n − 1
print([hyper(n, 2, 2) for n in range(1, 9)])# [4, 4, 4, 4, 4, 4, 4, 4]
print([hyper(n, 3, 3) for n in range(1, 5)])# [6, 9, 27, 7625597484987]
print([x for x in range(0, 1001) if x + x == x * x])# [0, 2]
L·36nombres harmoniques et Stirling
\(H_n=1+\tfrac12+\dots+\tfrac1n\)
=
\(\dfrac{1}{n!}\genfrac{[}{]}{0pt}{}{n+1}{2}\)

où \(\genfrac{[}{]}{0pt}{}{n+1}{2}\) compte les permutations de \(n+1\) objets à exactement deux cycles (Stirling de première espèce, L·24). Additionner les fractions sur le dénominateur commun \(n!\), sans simplifier, donne ces numérateurs : 1, 3, 11, 50, 274… (A000254). Une fois simplifiée, \(H_n\) = A001008/A002805 : 1, 3/2, 11/6, 25/12, 137/60, 49/20… Le rapport \(n!/\operatorname{PPCM}(1,\dots,n)\) (A025527) mesure ce que la simplification enlève. Quand \(n\) grandit, \(H_n-\ln n\) tend vers \(\gamma\) (XI·2).

sorte loifamille nombres harmoniques
# n = 1 à 30 en fractions exactes ; numérateurs sur n!, puis Hₙ simplifié
from fractions import Fraction
from math import factorial
s = [[1]]                                     # Stirling 1re espèce (L·24, poids n − 1)
for n in range(1, 32):
    prev = s[-1] + [0]
    s.append([(prev[k-1] if k else 0) + (n-1)*prev[k] for k in range(n+1)])
H = [Fraction(0)]
for n in range(1, 31): H.append(H[-1] + Fraction(1, n))
print(all(Fraction(s[n+1][2], factorial(n)) == H[n] for n in range(1, 31)))# True
print([s[n+1][2] for n in range(1, 8)])# [1, 3, 11, 50, 274, 1764, 13068]
print([str(H[n]) for n in range(1, 8)])# ['1', '3/2', '11/6', '25/12', '137/60', '49/20', '363/140']
L·37Hₙ n'est jamais entier
\(H_n\ \ (n\geq2)\)
\(\notin\)
\(\mathbb Z\)

Theisinger, 1915. Soit \(2^{k}\) la plus grande puissance de 2 qui ne dépasse pas \(n\) : \(\tfrac1{2^{k}}\) est le seul terme dont le dénominateur contient \(2^{k}\). En multipliant toute la somme par \(\operatorname{PPCM}(1,\dots,n)/2\), tous les termes deviennent entiers sauf celui-là, qui devient un demi-entier : la somme ne peut donc pas être entière. En prime, le numérateur de \(H_n\) est toujours impair, et son dénominateur contient exactement \(2^{k}\).

sorte loifamille nombres harmoniques
# n = 2 à 3000, fractions exactes : dénominateur divisible par 2^k et pas plus, numérateur impair
from fractions import Fraction
H, ok = Fraction(0), True
for n in range(1, 3001):
    H += Fraction(1, n)
    k = n.bit_length() - 1                     # 2^k ≤ n < 2^(k+1)
    d = H.denominator
    ok &= n == 1 or (d % 2**k == 0 and d % 2**(k+1) != 0 and H.numerator % 2 == 1)
print(ok)                     # True
L·38théorème de Wolstenholmecité · Wolstenholme 1862
\(\operatorname{num}H_{p-1}\)
\(\equiv\)
\(0\pmod{p^{2}}\)

pour tout premier \(p\geq5\) (Wolstenholme, 1862) : le numérateur de \(1+\tfrac12+\dots+\tfrac1{p-1}\) est divisible par \(p^{2}\). C'est pour cela qu'on appelle aussi ces numérateurs « nombres de Wolstenholme ». Forme équivalente : \(\binom{2p-1}{p-1}\equiv1\pmod{p^{3}}\). Les premiers qui vont un cran plus loin (\(p^{4}\) pour le binomial) sont les « premiers de Wolstenholme » : on n'en connaît que deux, 16 843 et 2 124 679. Le code retrouve le premier.

sorte loifamille nombres harmoniques
# p premier de 5 à 400 ; puis recherche des premiers de Wolstenholme jusqu'à 20 000
from fractions import Fraction
from math import comb
est_premier = lambda p: p > 1 and all(p % q for q in range(2, int(p**0.5)+1))
premiers = [p for p in range(5, 400) if est_premier(p)]
H = lambda n: sum(Fraction(1, k) for k in range(1, n+1))
print(all(H(p-1).numerator % p**2 == 0 for p in premiers))# True
print(all(comb(2*p-1, p-1) % p**3 == 1 for p in premiers))# True
def binom_mod(p, m):                          # C(2p−1, p−1) modulo m, sans le calculer en entier
    c = 1
    for i in range(1, p): c = c * (p+i) % m * pow(i, -1, m) % m
    return c
print([p for p in range(5, 20000) if est_premier(p) and binom_mod(p, p**4) == 1])# [16843]
L·39série de Mercator (Maclaurin du logarithme)
\(\ln(1+x)\)
=
\(x-\frac{x^{2}}{2}+\frac{x^{3}}{3}-\frac{x^{4}}{4}+\cdots\)

pour \(-1

sorte loifamille logarithmes
# 100 tirages dans ]−1, 1] ; le module ; puis le piège de la virgule flottante pour A = 10⁻¹⁵
from mpmath import mp, mpf, log, log10, nsum, inf, nstr
import math, random
mp.dps = 25
random.seed(1)
merc = lambda x: nsum(lambda k: mpf(-1)**(k+1) * x**k / k, [1, inf])
print(nstr(max(abs(merc(x) - log(1+x)) for x in (mpf(random.uniform(-0.9, 1)) for _ in range(100))), 3))# 0.0
print(1/log(10))                              # le module M = log₁₀ e# 0.4342944819032518276511289
A = 1e-15                                     # en virgule flottante (double) :
print(math.log10(1 + A))                      # naïf : 1 + A est arrondi d'abord# 4.821637332766433e-16
print(A / math.log(10))                       # la formule A × M# 4.342944819032518e-16
print(math.log1p(A) / math.log(10))           # la fonction prévue pour ça# 4.3429448190325156e-16
with mp.workdps(50):                          # la référence : 50 chiffres,
    ref = log10(1 + mpf('1e-15'))             # sinon 1 + A tronque A là aussi
print(nstr(ref, 17))          # 4.3429448190325161e-16
L·40théorème d'Euler–Fermat
\(a^{\varphi(n)}\)
\(\equiv\)
\(1\pmod{n}\)

pour tout entier \(a\) premier avec \(n\) (Euler, 1763). Idée de preuve : multiplier par \(a\) ne fait que mélanger les \(\varphi(n)\) restes premiers avec \(n\) ; le produit de ces restes est donc le même avant et après, ce qui force \(a^{\varphi(n)}\equiv1\). Pour \(n=p\) premier, c'est le petit théorème de Fermat (1640) : \(a^{p-1}\equiv1\pmod p\). La réciproque est fausse : les nombres de Carmichael, comme \(561=3\cdot11\cdot17\), vérifient \(a^{n-1}\equiv1\) pour tout \(a\) premier avec eux sans être premiers. Un contre-exemple à Lehmer (C·1) serait forcément un tel nombre, avec en plus \(\varphi(n)\mid n-1\) ; pour 561, \(\varphi=320\) ne divise pas 560.

sorte loifamille nombres premiers ; indicatrice φ
# n < 300 et tous les a premiers avec n ; puis les nombres de Carmichael sous 10 000
from math import gcd
phi = lambda n: sum(1 for k in range(1, n+1) if gcd(k, n) == 1)
print(all(pow(a, phi(n), n) == 1 for n in range(2, 300) for a in range(1, n) if gcd(a, n) == 1))# True
est_premier = lambda n: n > 1 and all(n % q for q in range(2, int(n**0.5)+1))
carmichael = [n for n in range(3, 10000, 2) if not est_premier(n)
              and all(pow(a, n-1, n) == 1 for a in range(2, n) if gcd(a, n) == 1)]
print(carmichael)             # [561, 1105, 1729, 2465, 2821, 6601, 8911]
print(phi(561), 560 % phi(561))# 320 240
L·41le piège des racines
\(\sqrt a\,\sqrt b\)
=
\(\sqrt{ab}\)

vrai dès que \(a\) et \(b\) ne sont pas tous deux négatifs, et en particulier pour \(a,b\geq0\). Pour \(a,b>0\), on en tire par exemple \(\dfrac{\sqrt a\sqrt b}{a}=\dfrac{b}{\sqrt a\sqrt b}=\dfrac{\sqrt b}{\sqrt a}\). Quand \(a\) et \(b\) sont tous deux négatifs, le signe bascule : \(\sqrt a\sqrt b=-\sqrt{ab}\). C'est ce qui démonte la fausse preuve célèbre \(-1=i\cdot i=\sqrt{-1}\sqrt{-1}=\sqrt{(-1)(-1)}=\sqrt1=1\) : l'erreur est au troisième signe égal.

sorte loifamille opérations
# a, b ≥ 0 ; signes mélangés ; tous deux négatifs (où le signe bascule) ; puis la fausse preuve
from mpmath import mp, mpf, sqrt, nstr
import random
mp.dps = 25
random.seed(1)
tir = lambda lo, hi: mpf(random.uniform(lo, hi))
pos = max(abs(sqrt(a)*sqrt(b) - sqrt(a*b)) for a, b in ((tir(0, 9), tir(0, 9)) for _ in range(200)))
mix = max(abs(sqrt(a)*sqrt(b) - sqrt(a*b)) for a, b in ((tir(-9, 0), tir(0, 9)) for _ in range(200)))
neg = max(abs(sqrt(a)*sqrt(b) + sqrt(a*b)) for a, b in ((tir(-9, 0), tir(-9, 0)) for _ in range(200)))
print(nstr(pos, 3), nstr(mix, 3), nstr(neg, 3))# 1.03e-25 2.07e-25 2.07e-25
print(sqrt(-1)*sqrt(-1), sqrt((-1)*(-1)))# (-1.0 + 0.0j) 1.0
L·42aire entre deux courbes
\(\text{aire entre }f\text{ et }g\text{ sur }[a,b]\)
=
\(\int_a^b\bigl|f(x)-g(x)\bigr|\,dx\)

on additionne de fines bandes verticales de largeur \(dx\), comme Zu découpe la boule en tranches (L·10). Deux pièges que les aide-mémoire taisent souvent. Premier piège : \(\int_a^b f(x)\,dx\) n'est l'aire sous la courbe que si \(f\geq0\) ; les parties sous l'axe comptent négativement, et \(\int_0^{2\pi}\sin x\,dx=0\) alors que l'aire coloriée vaut 4. Second piège : \(\int_a^b(f-g)\) n'est l'aire entre les courbes que si \(f\) reste au-dessus de \(g\) ; sinon, il faut couper aux points de croisement, ou prendre la valeur absolue. On peut aussi découper en bandes horizontales (\(dy\)) quand les courbes s'écrivent plus simplement en \(x=f(y)\).

sorte loifamille intégrales célèbres
# aire signée contre aire vraie, pour sin puis pour sin − cos ; puis un découpage en dy (9/2)
from mpmath import mp, quad, sin, cos, pi, fabs, sqrt, nstr
mp.dps = 25
print(nstr(quad(sin, [0, 2*pi]), 3))            # aire signée : les deux arches s'annulent# -1.36e-31
print(quad(lambda x: fabs(sin(x)), [0, pi, 2*pi]))# 4.0
# entre sin et cos sur [0, 2π] : ils se croisent en π/4 et 5π/4
print(nstr(quad(lambda x: sin(x) - cos(x), [0, 2*pi]), 3))# -3.76e-26
print(quad(lambda x: fabs(sin(x) - cos(x)), [0, pi/4, 5*pi/4, 2*pi]))# 5.656854249492380195206755
print(4*sqrt(2))              # 5.656854249492380195206755
# en bandes horizontales : entre x = y² et x = y + 2, de y = −1 à y = 2
print(quad(lambda y: (y + 2) - y**2, [-1, 2]))# 4.5
L·43PGCD × PPCM
\(\operatorname{pgcd}(a,b)\cdot\operatorname{ppcm}(a,b)\)
=
\(a\,b\)

pour deux entiers \(a,b\geq1\), et seulement pour deux. Pour trois, la bonne formule est une inclusion–exclusion : \(\operatorname{ppcm}(a,b,c)=\dfrac{abc\,\operatorname{pgcd}(a,b,c)}{\operatorname{pgcd}(a,b)\,\operatorname{pgcd}(b,c)\,\operatorname{pgcd}(a,c)}\). La version naïve échoue dès trois nombres : pour \(1,2,\dots,n\), le PGCD vaut 1, mais \(n!\) dépasse \(\operatorname{ppcm}(1,\dots,n)\) d'un facteur 1, 1, 1, 2, 2, 12, 12, 48, 144… (A025527). Pour les fractions, on prend le PGCD des numérateurs sur le PPCM des dénominateurs (et inversement pour le PPCM) : \(\operatorname{pgcd}\bigl(\tfrac12,\tfrac13,\dots,\tfrac1n\bigr)=1/\operatorname{ppcm}(2,\dots,n)\), soit 1/A003418(n), et \(\operatorname{pgcd}\bigl(\tfrac1a,\tfrac1b\bigr)\cdot\operatorname{ppcm}\bigl(\tfrac1a,\tfrac1b\bigr)=\tfrac1{ab}\).

sorte loifamille fonctions arithmétiques
# 10 000 paires, 10 000 triplets, l'écart n!/ppcm, puis les fractions
from math import gcd, lcm, factorial
from fractions import Fraction as Fr
from functools import reduce
import random
random.seed(1)
tir = lambda: random.randint(1, 10**6)
print(all(gcd(a, b)*lcm(a, b) == a*b for a, b in ((tir(), tir()) for _ in range(10000))))# True
print(all(lcm(a, b, c)*gcd(a, b)*gcd(b, c)*gcd(a, c) == a*b*c*gcd(a, b, c)# True
          for a, b, c in ((tir(), tir(), tir()) for _ in range(10000))))
ppcm = lambda n: reduce(lcm, range(1, n+1))
print([factorial(n) // ppcm(n) for n in range(1, 11)])# [1, 1, 1, 2, 2, 12, 12, 48, 144, 1440]
pgcd_fr = lambda x, y: Fr(gcd(x.numerator, y.numerator), lcm(x.denominator, y.denominator))
ppcm_fr = lambda x, y: Fr(lcm(x.numerator, y.numerator), gcd(x.denominator, y.denominator))
print(all(reduce(pgcd_fr, [Fr(1, k) for k in range(2, n+1)]) == Fr(1, ppcm(n)) for n in range(2, 40)))# True
print(all(pgcd_fr(Fr(1, a), Fr(1, b))*ppcm_fr(Fr(1, a), Fr(1, b)) == Fr(1, a*b)# True
          for a in range(1, 60) for b in range(1, 60)))
L·44cosinus et sinus par l'exponentielle
\(\cos\theta\)
=
\(\dfrac{e^{i\theta}+e^{-i\theta}}{2}\)

et \(\sin\theta=\dfrac{e^{i\theta}-e^{-i\theta}}{2i}\), pour tout \(\theta\) : c'est la formule d'Euler (L·33) retournée, en additionnant ou soustrayant \(e^{i\theta}\) et \(e^{-i\theta}\). Elle transforme la trigonométrie en calcul d'exponentielles ; par exemple \(1+\cos(2\pi x)=\tfrac12e^{-2\pi ix}+1+\tfrac12e^{2\pi ix}=2\cos^{2}(\pi x)\). Les angles sont en radians : 1 radian vaut \(180/\pi\) degrés.

sorte loifamille exponentielle complexe
# 200 tirages complexes ; puis 1 + cos(2πx) sous ses trois formes
from mpmath import mp, mpf, mpc, exp, cos, sin, pi, j, nstr
import random
mp.dps = 25
random.seed(1)
err = 0
for _ in range(200):
    t = mpc(random.uniform(-20, 20), random.uniform(-3, 3))        # complexe compris
    err = max(err, abs(cos(t) - (exp(j*t) + exp(-j*t))/2),
                   abs(sin(t) - (exp(j*t) - exp(-j*t))/(2*j)))
print(nstr(err, 3))           # 2.13e-25
x = mpf('0.3')
print(nstr(abs(1 + cos(2*pi*x) - (exp(-2*pi*j*x)/2 + 1 + exp(2*pi*j*x)/2)), 3),# 0.0 1.29e-26
      nstr(abs(1 + cos(2*pi*x) - 2*cos(pi*x)**2), 3))
L·45série de Gregory (arctangente)
\(\arctan x\)
=
\(x-\dfrac{x^{3}}{3}+\dfrac{x^{5}}{5}-\dfrac{x^{7}}{7}+\cdots\)

pour \(|x|\leq1\) seulement (Gregory, 1671 ; Madhava l'avait trouvée vers 1400). En degrés, avec \(x=\tan A\) : \(\tfrac{\pi}{180}A=\tan A-\tfrac13\tan^{3}A+\tfrac15\tan^{5}A-\dots\), valable pour \(-45°\leq A\leq45°\). À \(A=45°\), c'est Leibniz (I·2) ; à 60°, \(\tan A=\sqrt3>1\) et la série diverge. Leibniz est d'une lenteur désespérante (1 000 termes pour 3 chiffres). Machin (1706) a contourné le problème : \(\tfrac{\pi}{4}=4\arctan\tfrac15-\arctan\tfrac1{239}\), où chaque terme apporte environ 1,4 chiffre ; il en a tiré 100 décimales de π à la main.

sorte loifamille β de Dirichlet ; exponentielle complexe
# 100 tirages dans ]−1, 1[ ; la version en degrés ; Leibniz ; la divergence au-delà de 45° ; puis Machin
from mpmath import mp, mpf, atan, tan, pi, sqrt, nstr
import random
mp.dps = 30                                    # chiffres de garde
random.seed(1)
greg = lambda x, N: sum(mpf(-1)**k * x**(2*k+1)/(2*k+1) for k in range(N))
err = max(abs(greg(x, 400) - atan(x)) for x in (mpf(random.uniform(-0.9, 0.9)) for _ in range(100)))
A = mpf(30)                                    # un angle en degrés
deg = (pi*A/180, greg(tan(A*pi/180), 200))
leib = 4*greg(mpf(1), 1000)
machin = 4*(4*greg(mpf(1)/5, 21) - greg(mpf(1)/239, 21))
mp.dps = 25
print(nstr(err, 3))           # 8.87e-31
print(deg[0], deg[1])         # 0.5235987755982988730771072 0.5235987755982988730771072
print(nstr(leib, 10))                          # Leibniz, 1 000 termes# 3.140592654
print(nstr(greg(sqrt(3), 20), 6), nstr(greg(sqrt(3), 21), 6))   # 60° : ça diverge# -3.82045e+7 1.09095e+8
print(machin)                                  # Machin, 21 termes# 3.141592653589793238462643
print(pi)                     # 3.141592653589793238462643
L·46le polygone régulier
\(\mathcal A_n\)
=
\(\tfrac14\,n\,b^{2}\cot\dfrac{\pi}{n}\)

aire du polygone régulier à \(n\geq3\) côtés de longueur \(b\) (en degrés, \(\cot(180°/n)\)) ; son périmètre vaut \(nb\). L'aire est aussi le demi-produit du périmètre par l'apothème \(\tfrac b2\cot\tfrac\pi n\) : c'est L·15 (\(V=rS/n\)) en dimension 2. Inscrit dans un cercle de rayon \(R\), le côté vaut \(b=2R\sin\tfrac\pi n\), l'aire \(\tfrac n2R^{2}\sin\tfrac{2\pi}{n}\), et elle tend vers \(\pi R^{2}\) quand \(n\) grandit, comme le demi-périmètre tend vers \(\pi R\) (V·2).

sorte loifamille Viète ; boules et sphères
# 100 polygones tirés au hasard, aire par les sommets ; puis un million de côtés
from mpmath import mp, mpf, cos, sin, cot, pi, fsum, nstr
import random
mp.dps = 25
random.seed(1)
def polygone(n, b):                            # sommets réels, puis aire par la formule du lacet
    R = b / (2*sin(pi/n))
    P = [(R*cos(2*pi*k/n), R*sin(2*pi*k/n)) for k in range(n)]
    return abs(fsum(P[k][0]*P[(k+1) % n][1] - P[(k+1) % n][0]*P[k][1] for k in range(n))) / 2
err = 0
for _ in range(100):
    n, b = random.randint(3, 40), mpf(random.uniform(0.1, 10))
    A = n*b**2*cot(pi/n)/4
    err = max(err, abs(polygone(n, b) - A)/A,
                   abs(A - (n*b)*(b/2*cot(pi/n))/2)/A)       # ½ × périmètre × apothème
print(nstr(err, 3))           # 4.77e-26
n = 10**6
print(nstr(n/2*sin(2*pi/n), 15), nstr(pi, 15))           # rayon 1 : l'aire tend vers π# 3.14159265356912 3.14159265358979
L·47le produit d'Euler
\(\sum_{n=1}^{\infty}\frac1{n^{s}}\)
=
\(\prod_{p\ \text{premier}}\frac{1}{1-p^{-s}}\)

pour \(\operatorname{Re}s>1\) (Euler, 1737). Le mécanisme est un crible d'Ératosthène écrit en analyse : multiplier \(\zeta(s)\) par \((1-2^{-s})\) retire tous les termes pairs (II·5), puis \((1-3^{-s})\) retire les multiples de 3, et ainsi de suite ; quand tous les premiers ont criblé, il ne reste que le terme 1. En \(s=1\), la série harmonique diverge, donc le produit aussi : il y a une infinité de nombres premiers (preuve d'Euler). Plus finement, Mertens (1874) : \(\prod_{p\leq x}\frac{1}{1-1/p}\approx e^{\gamma}\ln x\), où revient la constante d'Euler (XI·2). Ses cousins : \(1/\zeta(s)=\sum\mu(n)/n^{s}\) (VIII·2) et \(-\zeta'/\zeta=\sum\Lambda(n)/n^{s}\) (L·30).

sorte loifamille nombres premiers ; valeurs de ζ
# un s complexe ; le crible après 2, 3, 5, 7 ; puis Mertens
N = 10**6
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, int(N**0.5)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
premiers = [q for q in range(N+1) if crible[q]]
from mpmath import mp, mpf, mpc, zeta, fprod, log, euler, exp, nstr
mp.dps = 20
s = mpc(3, 2)                                  # un s complexe, Re s > 1
print(nstr(abs(fprod(1/(1 - mpf(q)**-s) for q in premiers[:20000]) - zeta(s)), 3))# 5.47e-13
c = [1]*201                                    # le crible sur les coefficients de ζ
for q in (2, 3, 5, 7):
    for n in range(200, 0, -1):
        if n % q == 0: c[n] -= c[n // q]       # multiplier par (1 − q⁻ˢ)
print([n for n in range(1, 201) if c[n]][:16])# [1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67]
mertens = lambda x: fprod(1/(1 - mpf(1)/q) for q in premiers if q <= x) / log(x)
print([nstr(mertens(x), 6) for x in (10**2, 10**4, 10**6)])   # Mertens, en s = 1# ['1.80479', '1.78327', '1.78114']
print(nstr(exp(euler), 6))    # 1.78107
L·48théorème de Lagrange sur les fractions continues
\(x\ \text{a une fraction continue périodique}\)
\(\Longleftrightarrow\)
\(x\ \text{est racine d'une équation du 2}^{\text{e}}\text{ degré}\)

pour tout irrationnel réel \(x\). Euler a prouvé un sens (périodique implique quadratique, 1737), Lagrange l'autre (1770). Exemples : \(\sqrt2=[1;2,2,2,\dots]\), \(\sqrt3=[1;1,2,1,2,\dots]\), \(\sqrt7=[2;1,1,1,4,\dots]\), et \(\varphi=[1;1,1,\dots]\) (XIII·1). Pour \(\sqrt n\), la période finit toujours par \(2a_0\). À l'inverse, \(e\) (XIII·2) et \(\pi\) n'ont pas de période : ils ne sont pas quadratiques.

sorte loifamille fractions continues
# quelques racines ; les 283 non-carrés jusqu'à 300 reconstruits ; puis la période qui se ferme sur 2a₀
from math import isqrt
from mpmath import mp, mpf, sqrt, nstr
mp.dps = 30
def fc_racine(n, nb):                          # algorithme exact en entiers pour √n
    a0 = isqrt(n); m, d, a, t = 0, 1, a0, [a0]
    while len(t) < nb:
        m = d*a - m; d = (n - m*m)//d; a = (a0 + m)//d; t.append(a)
    return t
def valeur(t):
    v = mpf(t[-1])
    for a in reversed(t[:-1]): v = a + 1/v
    return v
print({n: fc_racine(n, 9) for n in (2, 3, 7, 13)})# {2: [1, 2, 2, 2, 2, 2, 2, 2, 2], 3: [1, 1, 2, 1, 2, 1, 2, 1, 2], 7: [2, 1, 1, 1, 4, 1, 1, 1, 4], 13: [3, 1, 1, 1, 1, 6, 1, 1, 1]}
non_carres = [n for n in range(2, 301) if isqrt(n)**2 != n]
print(nstr(max(abs(valeur(fc_racine(n, 60)) - sqrt(n)) for n in non_carres), 3))# 1.58e-30
def periode_finit_par_2a0(n):
    t = fc_racine(n, 2*n + 5); a0 = t[0]
    k = t.index(2*a0)                          # la première fois qu'apparaît 2a₀…
    return t[1:k+1] == t[k+1:2*k+1]            # … ferme bien une période qui se répète
print(all(periode_finit_par_2a0(n) for n in non_carres))# True
L·49théorème de Galois : la période renversée
\(-\dfrac{1}{\bar x}\)
=
\([\,\overline{a_{n-1};\,\dots,\,a_1,\,a_0}\,]\)

si \(x=[\,\overline{a_0;a_1,\dots,a_{n-1}}\,]\) est purement périodique, où \(\bar x\) est l'autre racine de son équation du second degré (son « conjugué »). C'est le premier article publié par Galois, en 1829, à 17 ans. Il prouve aussi qu'une fraction continue est purement périodique exactement quand \(x>1\) et \(-1<\bar x<0\). Pour \(\varphi=[\,\overline{1}\,]\), la période se lit pareil à l'envers : \(-1/\bar\varphi=\varphi\), c'est-à-dire \(\bar\varphi=-1/\varphi\approx-0{,}618\).

sources

É. Galois, « Démonstration d'un théorème sur les fractions continues périodiques », Annales de mathématiques pures et appliquées (Gergonne), 1829.

sorte loifamille fractions continues
# 200 périodes tirées au hasard ; puis l'exemple (1, 2, 3, 4)
from mpmath import mp, mpf, sqrt, nstr
import random
mp.dps = 40
random.seed(1)
def racines(per):                              # x = [per; x] ⇒ q x² + (q' − p) x − p' = 0
    p, pp, q, qq = 1, 0, 0, 1
    for a in per: p, pp, q, qq = a*p + pp, p, a*q + qq, q
    A, B, C = q, qq - p, -pp
    D = sqrt(B*B - 4*A*C)
    return (-B + D)/(2*A), (-B - D)/(2*A)       # x, et son conjugué
def valeur(t):
    v = mpf(t[-1])
    for a in reversed(t[:-1]): v = a + 1/v
    return v
ok = True
for _ in range(200):
    per = [random.randint(1, 9) for _ in range(random.randint(1, 5))]
    x, xb = racines(per)
    ok &= -1 < xb < 0 and abs(-1/xb - valeur(per[::-1]*(200//len(per)))) < mpf(10)**-25
print(ok)                     # True
x, xb = racines([1, 2, 3, 4])
print(nstr(xb, 12), nstr(-1/xb, 12), nstr(valeur([4, 3, 2, 1]*40), 12))# -0.232666399786 4.29799919936 4.29799919936
L·50formule de Faulhaber (sommes de puissances)
\(\sum_{k=1}^{n}k^{p}\)
=
\(\dfrac{1}{p+1}\sum_{j=0}^{p}\binom{p+1}{j}B_j^{+}\,n^{\,p+1-j}\)

où les \(B_j^{+}\) sont les nombres de Bernoulli avec la convention \(B_1^{+}=+\tfrac12\) (les autres sont inchangés : 1, 1/6, 0, −1/30…). Attention au piège : avec la convention \(B_1=-\tfrac12\), la même formule s'arrête à \(n-1\) (pour \(p=1\), \(n=3\), elle donne 3 au lieu de 6). On peut aussi garder \(B_1=-\tfrac12\) et écrire \((-1)^{j}B_j\), ou passer par les polynômes de Bernoulli : \(\sum_{k=0}^{n}k^{p}=\bigl(B_{p+1}(n+1)-B_{p+1}(0)\bigr)/(p+1)\). Faulhaber (1631) calculait ces sommes à la main jusqu'à \(p=17\) ; Jacques Bernoulli (1713) se vantait d'obtenir \(1^{10}+\dots+1000^{10}\) en moins d'un quart d'heure. Cas \(p=3\), le théorème de Nicomaque : \(1^{3}+2^{3}+\dots+n^{3}=(1+2+\dots+n)^{2}\), une pile de cubes qui forme un carré.

sorte loifamille comptage ; valeurs de ζ
# p = 0 à 11, n = 1 à 29 en fractions exactes ; le piège de B₁ ; Bernoulli 1713 ; Nicomaque
from fractions import Fraction as Fr
from math import comb
B = [Fr(1)]                                    # Bernoulli, convention B₁ = −½
for m in range(1, 16): B.append(-sum(comb(m+1, j)*B[j] for j in range(m)) / (m+1))
Bplus = B[:]; Bplus[1] = Fr(1, 2)
faul = lambda n, p, b: sum(comb(p+1, j)*b[j]*n**(p+1-j) for j in range(p+1)) / Fr(p+1)
somme = lambda n, p: sum(k**p for k in range(1, n+1))
print(all(faul(n, p, Bplus) == somme(n, p) for p in range(12) for n in range(1, 30)))# True
print(faul(3, 1, B), faul(3, 1, Bplus), somme(3, 1))      # le piège de la convention# 3 6 6
print(faul(1000, 10, Bplus))                   # le calcul de Jacques Bernoulli# 91409924241424243424241924242500
print(all(somme(n, 3) == somme(n, 1)**2 for n in range(1, 500)))   # Nicomaque# True
L·51la fonction génératrice des nombres de Bernoulli
\(\dfrac{x}{e^{x}-1}\)
=
\(\sum_{n\geq0}B_n\,\dfrac{x^{n}}{n!}\)

pour \(|x|<2\pi\) : la fonction explose en \(x=\pm2\pi i\), et c'est de là que vient le \((2\pi)^{2k}\) de L·25. Pourquoi les \(B_n\) impairs sont nuls (sauf \(B_1\)) : en notant \(B(x)\) cette fonction, \(B(-x)=\dfrac{xe^{x}}{e^{x}-1}=B(x)+x\). Dans \(B(-x)-B(x)\), les termes pairs s'annulent et les impairs se doublent, alors qu'un seul terme doit survivre, \(x\) : donc \(B_1=-\tfrac12\) et \(B_3=B_5=\dots=0\). Liens avec ζ : \(B_n=-n\,\zeta(1-n)\) pour \(n\geq2\) (pour \(n=1\), on obtient \(+\tfrac12\), l'autre convention), et \(\zeta(2k)\) en découle (L·25).

sorte loifamille comptage ; valeurs de ζ
# les Bₙ tirés de la série elle-même ; B(−x) = B(x) + x ; le rayon 2π ; puis Bₙ = −n ζ(1−n)
from fractions import Fraction as Fr
from math import factorial
from mpmath import mp, mpf, exp, bernoulli, zeta, nstr
import random
mp.dps = 30
N = 16
a = [Fr(1, factorial(k+1)) for k in range(N)]  # (eˣ − 1)/x = Σ xᵏ/(k+1)!
c = [Fr(1)]
for n in range(1, N): c.append(-sum(a[k]*c[n-k] for k in range(1, n+1)))   # on inverse la série
print([str(c[n]*factorial(n)) for n in range(9)])   # Bₙ = n! × coefficient# ['1', '-1/2', '1/6', '0', '-1/30', '0', '1/42', '0', '-1/30']
random.seed(1)
Bx = lambda x: x/(exp(x) - 1)
print(nstr(max(abs(Bx(-x) - Bx(x) - x) for x in (mpf(random.uniform(-5, 5)) for _ in range(100))), 3))# 2.47e-30
serie = lambda x, M: sum(bernoulli(n)*x**n/factorial(n) for n in range(M))
print(nstr(serie(mpf(5), 200) - Bx(mpf(5)), 3), nstr(serie(mpf(7), 200), 3))   # rayon 2π ≈ 6,28# 1.76e-20 2.16e+9
print(all(abs(-n*zeta(1-n) - bernoulli(n)) < mpf(10)**-20 for n in range(2, 30)), -1*zeta(0))# True 0.5
L·52racines primitives de l'unité et fonction de Mertens
\(\sum_{\substack{1\leq a\leq b\\ \operatorname{pgcd}(a,b)=1}}e^{2\pi i\,a/b}\)
=
\(\mu(b)\)

pour tout \(b\geq1\) : la somme des racines \(b\)-ièmes primitives de l'unité vaut la fonction de Möbius (VIII·2). Idée : toutes les racines \(b\)-ièmes se compensent (L·34), et on les regroupe selon leur ordre exact. En sommant sur toutes les fractions réduites \(a/b\) de dénominateur \(b\leq n\) (il y en a A002088(n), numérateurs A038566, dénominateurs A038567), on obtient la fonction de Mertens \(M(n)=\mu(1)+\dots+\mu(n)\) : 1, 0, −1, −1, −2, −1, −2… (A002321). L'hypothèse de Riemann (C·2) équivaut à ce que \(M(n)\) ne dépasse pas \(n^{1/2+\varepsilon}\). Mertens avait conjecturé \(|M(n)|<\sqrt n\) pour tout \(n>1\) : c'est faux, Odlyzko et te Riele l'ont réfuté en 1985, sans qu'on connaisse de contre-exemple explicite.

sorte loifamille nombres premiers ; exponentielle complexe
# b = 1 à 300 ; la somme de Farey contre M(n) ; puis |M(n)| < √n jusqu'à 10⁵ (vrai si loin, faux un jour)
import cmath
from math import gcd, pi, isqrt
N = 10**5
mu = [1]*(N+1); premier = [True]*(N+1)       # Möbius par crible
for q in range(2, N+1):
    if premier[q]:
        for m in range(q, N+1, q):
            if m > q: premier[m] = False
            mu[m] = -mu[m]
        for m in range(q*q, N+1, q*q): mu[m] = 0
prim = lambda b: sum(cmath.exp(2j*pi*a/b) for a in range(1, b+1) if gcd(a, b) == 1)
print(all(abs(prim(b) - mu[b]) < 1e-9 for b in range(1, 301)))# True
farey = lambda n: sum(prim(b) for b in range(1, n+1))
M = [0]
for k in range(1, N+1): M.append(M[-1] + mu[k])
print([round(farey(n).real) for n in range(1, 13)])# [1, 0, -1, -1, -2, -1, -2, -2, -2, -1, -2, -2]
print(M[1:13])                # [1, 0, -1, -1, -2, -1, -2, -2, -2, -1, -2, -2]
print(max(abs(M[n]) / n**0.5 for n in range(2, N+1)) < 1)# True
L·53les sauts du nombre de diviseurs du PPCM
\(\dfrac{d\bigl(\operatorname{ppcm}(1,\dots,n+1)\bigr)}{d\bigl(\operatorname{ppcm}(1,\dots,n)\bigr)}\)
=
\(\begin{cases}1 & \text{si }n+1\text{ n'est pas une puissance de premier}\\ 2 & \text{si }n+1\text{ est premier}\\ \frac{k+1}{k} & \text{si }n+1=p^{k},\ k\geq2\end{cases}\)

où \(d\) compte les diviseurs (A056793 est \(d(\operatorname{ppcm}(1,\dots,n))\)). Le PPCM ne change qu'en passant une puissance de premier : un nouveau premier double le nombre de diviseurs, et \(p^{k}\) fait passer l'exposant de \(p\) de \(k-1\) à \(k\), d'où le facteur \((k+1)/k\). Ce facteur vaut au plus \(\tfrac32\), atteint exactement aux carrés de premiers : 4, 9, 25, 49… Les \(n+1\) où rien ne bouge sont les nombres qui ne sont pas des puissances de premiers (A024619) : 6, 10, 12, 14, 15…

sorte loifamille nombres premiers ; fonctions arithmétiques
# n + 1 jusqu'à 300, PPCM factorisés pour de vrai ; puis les sauts non entiers
from math import lcm
from fractions import Fraction
est_premier = lambda m: m > 1 and all(m % q for q in range(2, int(m**0.5)+1))
def d(m):                                      # diviseurs, par vraie factorisation de m
    c, q = 1, 2
    while m > 1:
        e = 0
        while m % q == 0: m //= q; e += 1
        c *= e + 1; q += 1
    return c
def puissance(m):                              # (p, k) si m = p^k, sinon None
    for q in range(2, m+1):
        if m % q == 0:
            k = 0
            while m % q == 0: m //= q; k += 1
            return (q, k) if m == 1 else None
L = [1]
for n in range(1, 301): L.append(lcm(L[-1], n))
ok = True
for n in range(1, 300):
    r, pk = Fraction(d(L[n+1]), d(L[n])), puissance(n+1)
    ok &= r == (1 if pk is None else 2 if pk[1] == 1 else Fraction(pk[1]+1, pk[1]))
print(ok)                     # True
print([(n+1, str(Fraction(d(L[n+1]), d(L[n])))) for n in range(1, 60)# [(4, '3/2'), (8, '4/3'), (9, '3/2'), (16, '5/4'), (25, '3/2'), (27, '4/3'), (32, '6/5'), (49, '3/2')]
       if d(L[n+1]) != d(L[n]) and not est_premier(n+1)])
L·54théorème de Pick
\(\mathcal A\)
=
\(\dfrac{B}{2}+I-1\)

pour tout polygone simple (sans trou, sans croisement) dont les sommets sont sur une grille de pas 1 : \(B\) compte les points de la grille sur le bord, \(I\) ceux à l'intérieur (Pick, 1899). Exemple : un polygone à 12 sommets avec \(B=20\) et \(I=8\) a pour aire \(10+8-1=17\). Avec \(h\) trous, la formule devient \(\mathcal A=I+\tfrac B2-1+h\). En dimension 3, aucun équivalent n'existe : le tétraèdre de Reeve (1957), de sommets \((0,0,0),(1,0,0),(0,1,0),(1,1,r)\), n'a aucun point de la grille hormis ses quatre sommets, quel que soit \(r\), alors que son volume \(r/6\) grandit sans fin. Encore la dimension 2 qui se laisse faire, et la 3 qui se dérobe.

sorte loifamille empilements ; Viète
# ton polygone recompté ; 300 triangles au hasard ; puis les tétraèdres de Reeve (points, volume)
from math import gcd
from fractions import Fraction as Fr
import random
def pick(P):                                   # aire (lacet), bord et intérieur comptés pour de vrai
    n = len(P)
    A2 = abs(sum(P[i][0]*P[(i+1)%n][1] - P[(i+1)%n][0]*P[i][1] for i in range(n)))
    B = sum(gcd(abs(P[(i+1)%n][0]-P[i][0]), abs(P[(i+1)%n][1]-P[i][1])) for i in range(n))
    def bord(x, y):
        return any((b[0]-a[0])*(y-a[1]) == (b[1]-a[1])*(x-a[0]) and min(a[0],b[0]) <= x <= max(a[0],b[0])
                   and min(a[1],b[1]) <= y <= max(a[1],b[1]) for a, b in zip(P, P[1:]+P[:1]))
    def dedans(x, y):
        c = False
        for (x1, y1), (x2, y2) in zip(P, P[1:]+P[:1]):
            if (y1 > y) != (y2 > y) and x < x1 + Fr(y-y1)*(x2-x1)/(y2-y1): c = not c
        return c
    xs, ys = [q[0] for q in P], [q[1] for q in P]
    I = sum(1 for x in range(min(xs), max(xs)+1) for y in range(min(ys), max(ys)+1)
            if not bord(x, y) and dedans(x, y))
    return Fr(A2, 2), B, I
exemple = [(1,2),(3,2),(4,4),(6,2),(6,7),(5,6),(3,6),(2,7),(1,7),(1,5),(3,4),(1,3)]
A, B, I = pick(exemple)
print(A, B, I, Fr(B, 2) + I - 1)# 17 20 8 17
random.seed(1)
ok = True
for _ in range(300):                           # triangles de la grille tirés au hasard
    T = [(random.randint(-9, 9), random.randint(-9, 9)) for _ in range(3)]
    if (T[1][0]-T[0][0])*(T[2][1]-T[0][1]) == (T[2][0]-T[0][0])*(T[1][1]-T[0][1]): continue
    A, B, I = pick(T); ok &= A == Fr(B, 2) + I - 1
print(ok)                     # True
def points_reeve(r):                           # points de la grille dans le tétraèdre de Reeve
    S = [(0,0,0), (1,0,0), (0,1,0), (1,1,r)]
    def dedans(p):
        # coordonnées barycentriques exactes : p = S0 + u(S1−S0) + v(S2−S0) + w(S3−S0)
        x, y, z = p
        w = Fr(z, r); u = x - w; v = y - w
        return min(u, v, w, 1 - u - v - w) >= 0
    return sum(dedans((x, y, z)) for x in (0, 1) for y in (0, 1) for z in range(r+1))
print([(r, points_reeve(r), str(Fr(r, 6))) for r in (1, 2, 5, 20)])# [(1, 4, '1/6'), (2, 4, '1/3'), (5, 4, '5/6'), (20, 4, '10/3')]
L·55la forme polaire d'un nombre complexe
\(a+ib\)
=
\(A\,e^{i\theta}\)

avec \(A=\sqrt{a^{2}+b^{2}}\) et \(\theta=\operatorname{atan2}(b,a)\), c'est-à-dire \(\tan\theta=b/a\) (partie imaginaire sur partie réelle) dans le bon quadrant. Piège : \(\arctan(b/a)\) confond \(1+i\) et \(-1-i\), dont les angles diffèrent de π ; c'est la fonction Math.atan2 des langages de programmation qui tranche. En polaire, multiplier revient à multiplier les modules et additionner les angles (L·33). En physique, c'est le phaseur : un point qui tourne sur un cercle, \(A\,e^{i(\omega t+\varphi)}\), dont l'ombre sur l'axe réel est l'oscillation \(A\cos(\omega t+\varphi)\).

sorte loifamille exponentielle complexe
# 500 tirages avec atan2, et combien de fois arctan(b/a) se trompe ; le produit ; puis le phaseur
from mpmath import mp, mpf, mpc, sqrt, atan2, atan, exp, cos, pi, j, nstr
import random
mp.dps = 25
random.seed(1)
err, piege = 0, 0
for _ in range(500):
    a, b = mpf(random.uniform(-9, 9)), mpf(random.uniform(-9, 9))
    A, t = sqrt(a*a + b*b), atan2(b, a)
    err = max(err, abs(A*exp(j*t) - (a + j*b)))
    piege += abs(A*exp(j*atan(b/a)) - (a + j*b)) > 1e-10      # arctan se trompe quand a < 0
print(nstr(err, 3), piege)    # 3.27e-25 234
z1, z2 = mpc(1, 2), mpc(-3, 1)                 # produit : modules multipliés, angles ajoutés
print(nstr(abs(abs(z1*z2) - abs(z1)*abs(z2)), 3),# 0.0 1.29e-26
      nstr(abs(exp(j*(atan2(z1.imag, z1.real) + atan2(z2.imag, z2.real))) - z1*z2/abs(z1*z2)), 3))
A, w, phi, t = mpf(2), mpf(3), mpf('0.4'), mpf('1.7')              # le phaseur
print(nstr(abs((A*exp(j*(w*t + phi))).real - A*cos(w*t + phi)), 3))# 0.0
L·56la loi de Poisson, limite de la binomiale
\(\lim_{n\to\infty}\binom nk\Bigl(\frac\lambda n\Bigr)^{k}\Bigl(1-\frac\lambda n\Bigr)^{n-k}\)
=
\(e^{-\lambda}\dfrac{\lambda^{k}}{k!}\)

pour tout \(\lambda>0\) et tout entier \(k\geq0\) (Poisson, 1837). L'image du tissu : un long tissu présente en moyenne \(\lambda\) déchirures par mètre, indépendantes les unes des autres. On coupe le mètre en \(n\) morceaux si petits que chacun a au plus une déchirure, avec probabilité \(\lambda/n\) : c'est un pile ou face très déséquilibré, répété \(n\) fois, et la binomiale tend vers la loi de Poisson. Les probabilités somment à 1 grâce à la série de \(e\) (XI·1), et la moyenne vaut \(\lambda\). Même loi, ailleurs : le nombre de points fixes d'une permutation tirée au hasard suit Poisson(1), d'où la probabilité \(1/e\) des dérangements (XI·1). Et l'exemple historique de Bortkiewicz (1898) : les morts par ruade de cheval dans la cavalerie prussienne.

sorte loifamille probabilités ; comptage
# binomiale contre Poisson pour n = 10, 100, 10⁴ ; somme et moyenne ; puis les points fixes de 8! permutations
from itertools import permutations
from math import comb, factorial as fact, exp
from mpmath import mp, mpf, nsum, inf, factorial, e, nstr
mp.dps = 25
lam = 2.5
poisson = lambda k, l=lam: exp(-l) * l**k / fact(k)
binom = lambda k, n: comb(n, k) * (lam/n)**k * (1 - lam/n)**(n-k)
print([f'{max(abs(binom(k, n) - poisson(k)) for k in range(8)):.1e}' for n in (10, 100, 10**4)])# ['3.7e-02', '3.0e-03', '2.9e-05']
L = mpf(lam)
print(nstr(nsum(lambda k: e**-L * L**k / factorial(k), [0, inf]), 20),# 1.0 2.5
      nstr(nsum(lambda k: k * e**-L * L**k / factorial(k), [0, inf]), 20))
n = 8                                          # points fixes des 8! permutations
fixes = [sum(1 for i in range(n) if p[i] == i) for p in permutations(range(n))]
print([round(fixes.count(k)/fact(n), 4) for k in range(4)])# [0.3679, 0.3679, 0.184, 0.0611]
print([round(poisson(k, 1), 4) for k in range(4)])# [0.3679, 0.3679, 0.1839, 0.0613]
L·57le binôme de Newton
\((x+y)^{n}\)
=
\(\sum_{k=0}^{n}\binom nk\,x^{\,n-k}y^{k}\)

pour tout entier \(n\geq0\), avec \(\binom nk=C_n^{k}=\dfrac{n!}{k!\,(n-k)!}\) (Pascal, L·24). Avec \(y\) changé en \(-y\) : \((x-y)^{n}=\sum\binom nk x^{n-k}(-y)^{k}\). Avec \(x=y=1\), la ligne \(n\) du triangle somme à \(2^{n}\) ; avec \(x=1,\ y=-1\), la somme alternée est nulle. Newton (1665) l'a étendu à tout exposant \(\alpha\), réel ou complexe, pour \(|x|<1\) : \((1+x)^{\alpha}=\sum_{k\geq0}\binom\alpha k x^{k}\), où \(\binom\alpha k=\alpha(\alpha-1)\cdots(\alpha-k+1)/k!\) ; la série ne s'arrête alors plus. Exemple : \(1/\sqrt{1-4x}=\sum_k\binom{2k}{k}x^{k}\), où reviennent les binomiaux centraux de X·3.

sorte loifamille comptage
# 500 cas exacts ; les sommes de lignes ; 100 exposants réels ; puis les binomiaux centraux
from math import comb
from mpmath import mp, mpf, binomial, nsum, inf, sqrt, nstr
import random
mp.dps = 25
random.seed(1)
ok = True
for _ in range(500):                           # entiers exacts, n jusqu'à 30
    x, y, n = random.randint(-50, 50), random.randint(-50, 50), random.randint(0, 30)
    ok &= (x + y)**n == sum(comb(n, k) * x**(n-k) * y**k for k in range(n+1))
print(ok)                     # True
print([sum(comb(n, k) for k in range(n+1)) for n in range(8)])# [1, 2, 4, 8, 16, 32, 64, 128]
err = 0
for _ in range(100):                           # exposant quelconque (Newton 1665)
    a, x = mpf(random.uniform(-5, 5)), mpf(random.uniform(-0.8, 0.8))
    err = max(err, abs(nsum(lambda k: binomial(a, k) * x**k, [0, inf]) - (1 + x)**a))
print(nstr(err, 3))           # 0
x = mpf('0.1')
print(nstr(nsum(lambda k: binomial(2*k, k) * x**k, [0, inf]) - 1/sqrt(1 - 4*x), 3))# -2.58e-26
L·58la formule d'Euler–Maclaurin
\(\sum_{a
=
\(\sum_{r=0}^{k}\frac{(-1)^{r+1}B_{r+1}}{(r+1)!}\Bigl(f^{(r)}(b)-f^{(r)}(a)\Bigr)+R\)

pour \(a,b\) entiers et \(f\) de classe \(C^{k+1}\) sur \([a,b]\) (Euler 1732, Maclaurin 1742), avec la convention \(B_1=-\tfrac12\) et le reste \(R=\dfrac{(-1)^{k}}{(k+1)!}\displaystyle\int_a^b\tilde B_{k+1}(t)\,f^{(k+1)}(t)\,dt\), où \(\tilde B_{k+1}(t)=B_{k+1}(t-\lfloor t\rfloor)\) est le polynôme de Bernoulli répété périodiquement (L·59). C'est le pont entre sommes et intégrales ; les premiers termes sont \(\tfrac12(f(b)-f(a))+\tfrac1{12}(f'(b)-f'(a))-\dots\) Trois usages dans Idem : Stirling (X·5), l'écart harmonique \(H_n-\ln n\approx\gamma+\tfrac1{2n}-\tfrac1{12n^{2}}+\tfrac1{120n^{4}}\) (XI·2), et Faulhaber (L·50), où la formule devient exacte car les dérivées d'un polynôme finissent par s'annuler. En général, la série infinie diverge : on s'en sert comme d'un développement asymptotique, arrêté au bon moment.

sorte loifamille comptage ; valeurs de ζ
# la formule avec son reste, pour k = 1 à 4 ; puis Hₙ − ln n − γ à n = 10 contre son développement
from mpmath import mp, mpf, fsum, quad, diff, bernoulli, bernpoly, factorial, floor, linspace
from mpmath import harmonic, log, euler, nstr
mp.dps = 30
f = lambda t: 1/(1 + t**2)
a, b = 0, 6
def ecart(k):                                  # somme − intégrale − (termes + reste)
    somme = fsum(f(n) for n in range(a+1, b+1)) - quad(f, [a, b])
    termes = fsum((-1)**(r+1) * bernoulli(r+1) / factorial(r+1) * (diff(f, b, r) - diff(f, a, r))
                  for r in range(k+1))
    R = (-1)**k / factorial(k+1) * quad(lambda t: bernpoly(k+1, t - floor(t)) * diff(f, t, k+1),
                                        linspace(a, b, b - a + 1))
    return somme - termes - R
# à la précision près des dérivées numériques (≈ 10⁻¹⁷)
print([nstr(ecart(k), 3) for k in (1, 2, 3, 4)])# ['1.95e-17', '1.95e-17', '1.95e-17', '1.95e-17']
n = mpf(10)                                    # l'écart harmonique, développé
print(nstr(harmonic(n) - log(n) - euler, 15))# 0.0491674960726754
print(nstr(1/(2*n) - 1/(12*n**2) + 1/(120*n**4), 15))# 0.0491675
# l'écart restant, ≈ 4·10⁻⁹, est le terme suivant : −1/(252 n⁶)
L·59la série de Fourier des polynômes de Bernoulli
\(B_n(x)\)
=
\(-\dfrac{n!}{(2\pi i)^{n}}\sum_{k\neq0}\dfrac{e^{2\pi ikx}}{k^{n}}\)

pour \(0\leq x\leq1\) et \(n\geq2\) : le \(k\)-ième coefficient de Fourier de \(B_n\), répété périodiquement, vaut \(c_k=-\dfrac{n!}{(2i\pi k)^{n}}\). C'est la preuve de la formule d'Euler pour \(\zeta(2p)\) (L·25) : en \(x=0\) et \(n=2p\), les termes \(k\) et \(-k\) s'additionnent, et il vient \(B_{2p}=(-1)^{p+1}\dfrac{2\,(2p)!}{(2\pi)^{2p}}\zeta(2p)\), soit \(\displaystyle\sum_{n\geq1}\frac1{n^{2p}}=\frac{|B_{2p}|\,2^{2p-1}\pi^{2p}}{(2p)!}\). Pour \(n\) impair, la même série en \(x=0\) donne 0, ce qui ne dit rien de \(\zeta(3),\zeta(5),\dots\), et c'est pourquoi on ne leur connaît aucune forme close.

sorte loifamille valeurs de ζ ; comptage ; exponentielle complexe
# coefficients de Fourier pour n = 2 à 6 ; la série qui reconstruit B₄ ; puis ζ(2p) retrouvé
from mpmath import mp, mpf, quad, bernpoly, bernoulli, exp, pi, j, factorial, zeta, fsum, nstr
mp.dps = 25
coef = lambda n, k: quad(lambda x: bernpoly(n, x) * exp(-2*j*pi*k*x), [0, 1])
print(nstr(max(abs(coef(n, k) + factorial(n)/(2*j*pi*k)**n) for n in range(2, 7) for k in (1, 2, 3, -2)), 3))# 8.08e-28
x, n = mpf('0.3'), 4                            # la série reconstruit B₄(0,3)
serie = -factorial(n)/(2*j*pi)**n * fsum(exp(2*j*pi*k*x)/mpf(k)**n for k in range(-4000, 4001) if k)
print(nstr(serie.real, 12), nstr(bernpoly(n, x), 12))# 0.0107666666667 0.0107666666667
print([nstr(abs(bernoulli(2*p)) * 2**(2*p-1) * pi**(2*p) / factorial(2*p) - zeta(2*p), 3) for p in (1, 2, 3, 10)])# ['5.17e-26', '2.58e-26', '5.17e-26', '1.03e-25']
L·60les polynômes de Bernoulli
\(\dfrac{t\,e^{xt}}{e^{t}-1}\)
=
\(\sum_{n\geq0}B_n(x)\,\dfrac{t^{n}}{n!}\)

avec \(B_n(x)=\sum_{k=0}^{n}\binom nk B_k\,x^{\,n-k}\) (attention à l'exposant : \(n-k\), et non \(n-1\)), et \(B_n(0)=B_n\) (L·51). Trois propriétés font tout le travail. La différence : \(B_n(x+1)-B_n(x)=n\,x^{n-1}\), qui télescope les sommes de puissances, d'où Faulhaber : \(\sum_{k=0}^{m}k^{p}=\bigl(B_{p+1}(m+1)-B_{p+1}(0)\bigr)/(p+1)\) (L·50). Le miroir : \(B_n(1-x)=(-1)^{n}B_n(x)\), d'où les \(B_n\) impairs nuls. La dérivée : \(B_n'=n\,B_{n-1}\), avec \(\int_0^1B_n=0\) pour \(n\geq1\). Répétés périodiquement, ils ont la série de Fourier de L·59 et servent de noyau au reste d'Euler–Maclaurin (L·58).

n\(B_n(x)\)
0\(1\)
1\(x-\tfrac12\)
2\(x^{2}-x+\tfrac16\)
3\(x^{3}-\tfrac32x^{2}+\tfrac12x\)
4\(x^{4}-2x^{3}+x^{2}-\tfrac1{30}\)
5\(x^{5}-\tfrac52x^{4}+\tfrac53x^{3}-\tfrac16x\)
6\(x^{6}-3x^{5}+\tfrac52x^{4}-\tfrac12x^{2}+\tfrac1{42}\)
sorte loifamille comptage ; valeurs de ζ
# en fractions exactes : la différence, le miroir, l'intégrale nulle ; puis la fonction génératrice
from fractions import Fraction as Fr
from math import comb
B = [Fr(1)]                                    # nombres de Bernoulli, B₁ = −½
for m in range(1, 101): B.append(-sum(comb(m+1, j)*B[j] for j in range(m)) / (m+1))
from mpmath import mp, mpf, bernpoly, exp, factorial, nstr
Bx = lambda n, x: sum(comb(n, k) * B[k] * x**(n-k) for k in range(n+1))
xs = [Fr(i, 7) for i in range(-10, 30)]       # 40 points exacts : assez pour tout degré ≤ 39
print(all(Bx(n, x+1) - Bx(n, x) == n * x**(n-1) for n in range(1, 30) for x in xs))# True
print(all(Bx(n, 1-x) == (-1)**n * Bx(n, x) for n in range(30) for x in xs))# True
integrale = lambda n: sum(comb(n, k) * B[k] / (n-k+1) for k in range(n+1))   # ∫₀¹ Bₙ
print(all(integrale(n) == 0 for n in range(1, 30)))# True
mp.dps = 25
t, x = mpf('1.3'), mpf('0.4')
print(nstr(sum(bernpoly(n, x) * t**n / factorial(n) for n in range(80)) - t*exp(x*t)/(exp(t) - 1), 3))# 0.0
L·61théorème de von Staudt–Clausen
\(B_{2n}+\sum_{\substack{p\ \text{premier}\\ (p-1)\mid 2n}}\frac1p\)
\(\in\)
\(\mathbb Z\)

pour tout \(n\geq1\) (von Staudt et Clausen, indépendamment, 1840). Conséquence : le dénominateur de \(B_{2n}\) est exactement le produit des premiers \(p\) tels que \(p-1\) divise \(2n\), toujours multiple de 6 ; par exemple \(B_{12}=-691/2730\), et \(2730=2\cdot3\cdot5\cdot7\cdot13\). Le théorème ne vaut que pour les indices pairs : pour \(n\) impair \(\geq3\), \(B_n=0\) et il resterait \(\tfrac12\). Le numérateur 691 est célèbre : c'est le même 691 que dans la série thêta du réseau de Leech (L·23), et Ramanujan a prouvé \(\tau(n)\equiv\sigma_{11}(n)\pmod{691}\), où \(\tau\) sont les coefficients de \(\Delta\).

sorte loifamille comptage ; nombres premiers
# indices pairs jusqu'à 100 : l'entier, puis les dénominateurs ; B₁₂ ; l'indice 3 ; puis la congruence de Ramanujan
from fractions import Fraction as Fr
from math import comb
B = [Fr(1)]                                    # nombres de Bernoulli, B₁ = −½
for m in range(1, 101): B.append(-sum(comb(m+1, j)*B[j] for j in range(m)) / (m+1))
est_premier = lambda q: q > 1 and all(q % r for r in range(2, int(q**0.5)+1))
somme = lambda n: B[n] + sum(Fr(1, q) for q in range(2, n+2) if est_premier(q) and n % (q-1) == 0)
print(all(somme(n).denominator == 1 for n in range(2, 101, 2)))# True
from math import prod
print(all(B[n].denominator == prod(q for q in range(2, n+2) if est_premier(q) and n % (q-1) == 0)# True
          for n in range(2, 101, 2)))
print(B[12], somme(3))                          # 691/2730, puis l'échec aux indices impairs# -691/2730 1/2
N = 40                                         # Ramanujan : τ(n) ≡ σ₁₁(n) mod 691
P = [1] + [0]*N
for n in range(1, N+1):
    for _ in range(24):
        for k in range(N, n-1, -1): P[k] -= P[k-n]
tau = lambda n: P[n-1]
sigma11 = lambda n: sum(d**11 for d in range(1, n+1) if n % d == 0)
print(all((tau(n) - sigma11(n)) % 691 == 0 for n in range(1, N+1)))# True
L·62l'indicatrice des multiples d'un premier (Fermat)
\(\bigl((p-1)\,n^{\,p-1}+1\bigr)\bmod p\)
=
\(\begin{cases}1&\text{si }p\mid n\\ 0&\text{sinon}\end{cases}\)

pour tout premier \(p\) et tout entier \(n\) : c'est le petit théorème de Fermat (L·40) déguisé, puisque \(n^{p-1}\equiv1\) si \(p\nmid n\), et \(\equiv0\) sinon. Avec \(p=5\) : \((4n^{4}+1)\bmod5\) donne 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1… L'hypothèse « \(p\) premier » est indispensable, et même caractéristique : pour tout composé \(m\), un diviseur propre \(d\) de \(m\) fait échouer la formule, puisque \(d^{m-1}\) ne peut pas valoir 1 modulo \(m\). Avec 9, on obtient 1, 0, 6, 1, 3, 3, 1, 6, 0… La formule est donc aussi un test de primalité caché, très lent.

sorte loifamille nombres premiers ; fonctions arithmétiques
# p = 5 ; l'échec avec 9 ; puis les m jusqu'à 300 où la formule marche : exactement les premiers
est_premier = lambda q: q > 1 and all(q % r for r in range(2, int(q**0.5)+1))
indic = lambda m, n: ((m-1) * pow(n, m-1, m) + 1) % m
print([indic(5, n) for n in range(11)])# [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
print([indic(9, n) for n in range(9)])# [1, 0, 6, 1, 3, 3, 1, 6, 0]
marche = [m for m in range(2, 300) if all(indic(m, n) == (1 if n % m == 0 else 0) for n in range(3*m))]
print(marche == [m for m in range(2, 300) if est_premier(m)])# True
L·63sommes de produits d'entiers consécutifs
\(\sum_{k=1}^{n}k(k+1)\cdots(k+m-1)\)
=
\(\dfrac{n(n+1)\cdots(n+m)}{m+1}\)

pour tous entiers \(n,m\geq1\) : la somme des produits de \(m\) entiers consécutifs est le produit de \(m+1\) consécutifs, divisé par \(m+1\). Avec \(m=1\), \(1+2+\dots+n=n(n+1)/2\) ; avec \(m=2\), \(1\cdot2+2\cdot3+\dots+n(n+1)=\dfrac{n(n+1)(n+2)}{3}=\dfrac n3\,(n^{2}+3n+2)\). Attention à ne pas écrire \(+1\) à la fin : pour \(n=1\), on obtiendrait 5/3 au lieu de 2. Derrière la formule se cache l'identité « de la crosse de hockey » du triangle de Pascal, \(\sum_{k}\binom{k+m-1}{m}=\binom{n+m}{m+1}\), puisque \(k(k+1)\cdots(k+m-1)=m!\binom{k+m-1}{m}\).

sorte loifamille comptage
# m = 1 à 6 et n = 1 à 50 en entiers exacts ; le piège du « +1 » ; puis la crosse de hockey
from math import comb, prod
from fractions import Fraction as Fr
print(all(sum(prod(range(k, k+m)) for k in range(1, n+1)) * (m+1) == prod(range(n, n+m+1))# True
          for m in range(1, 7) for n in range(1, 51)))
print([sum(k*(k+1) for k in range(1, n+1)) for n in range(1, 6)])# [2, 8, 20, 40, 70]
print([str(Fr(n, 3)*(n*n + 3*n + 1)) for n in range(1, 6)])          # avec « +1 » : faux# ['5/3', '22/3', '19', '116/3', '205/3']
print(all(sum(comb(k+m-1, m) for k in range(1, n+1)) == comb(n+m, m+1)# True
          for m in range(1, 7) for n in range(1, 51)))              # crosse de hockey
L·64le théorème de Wilson
\((m-1)!+1\equiv0\pmod m\)
\(\Longleftrightarrow\)
\(m\ \text{premier}\)

pour tout entier \(m\geq2\) (énoncé par Waring en 1770, qui l'attribue à son élève Wilson, et démontré par Lagrange en 1771). Pour \(m\) composé, \((m-1)!\) est même divisible par \(m\), sauf pour \(m=4\) où il reste 2. Une conséquence : la somme \(1+2+\dots+n=n(n+1)/2\) divise \(n!\) exactement quand \(n+1\) n'est pas premier (pour \(n\geq2\)), car \(n!\big/\tfrac{n(n+1)}{2}=\dfrac{2\,(n-1)!}{n+1}\). Ce rapport est pair, sauf pour \(n=1\) et \(n=3\), où il vaut 1. Comme l'indicatrice de Fermat (L·62), c'est un test de primalité exact mais très lent.

sorte loifamille nombres premiers
# Wilson jusqu'à 2000 ; les restes pour les composés ; puis ta divisibilité et ses rapports impairs
from math import factorial
est_premier = lambda m: m > 1 and all(m % q for q in range(2, int(m**0.5)+1))
def fact_mod(m):                               # (m−1)! modulo m, sans calculer l'entier
    r = 1
    for k in range(2, m): r = r * k % m
    return r
print(all(((fact_mod(m) + 1) % m == 0) == est_premier(m) for m in range(2, 2001)))# True
print({m: fact_mod(m) for m in range(4, 26) if not est_premier(m)})# {4: 2, 6: 0, 8: 0, 9: 0, 10: 0, 12: 0, 14: 0, 15: 0, 16: 0, 18: 0, 20: 0, 21: 0, 22: 0, 24: 0, 25: 0}
T = lambda n: n*(n+1)//2
print(all((factorial(n) % T(n) == 0) == (not est_premier(n+1)) for n in range(2, 501)))# True
print([(n, factorial(n)//T(n)) for n in range(1, 501) if factorial(n) % T(n) == 0 and factorial(n)//T(n) % 2])# [(1, 1), (3, 1)]
L·65couper l'espace : régions en dimension d
\(R_d(n)\)
=
\(\sum_{k=0}^{d}\binom nk\)

nombre maximal de régions obtenues en coupant l'espace de dimension \(d\) par \(n\) hyperplans en position générale. En dimension 2, \(1+n+\binom n2=\tfrac{n(n+1)}2+1\) : 2, 4, 7, 11, 16, 22, 29, 37… (la suite « du traiteur paresseux », qui compte aussi les morceaux d'un disque coupé par \(n\) droites). En dimension 3, avec \(n\) plans : 1, 2, 4, 8, 15, 26, 42, 64… (les nombres du « gâteau »). La preuve tient dans la récurrence \(R_d(n)=R_d(n-1)+R_{d-1}(n-1)\) : le \(n\)-ième hyperplan est lui-même découpé en \(R_{d-1}(n-1)\) morceaux, et chacun coupe une région en deux. Tant que \(n\leq d\), on trouve \(2^{n}\), puis la croissance ralentit. Le piège voisin : en reliant \(n\) points d'un cercle par toutes leurs cordes, on obtient 1, 2, 4, 8, 16, puis 31 et non 32 (problème de Moser, \(1+\binom n2+\binom n4\)). Un motif n'est pas une preuve.

sorte loifamille comptage ; hypercubes
# formule contre récurrence pour d ≤ 6 et n ≤ 30 ; les suites en dimensions 2 et 3 ; puis le piège de Moser
from math import comb
from functools import lru_cache
R = lambda d, n: sum(comb(n, k) for k in range(d+1))
@lru_cache(None)
def rec(d, n):                                 # la récurrence de la preuve
    if n == 0 or d == 0: return 1
    return rec(d, n-1) + rec(d-1, n-1)
print(all(R(d, n) == rec(d, n) for d in range(7) for n in range(31)))# True
print([R(2, n) for n in range(1, 9)])# [2, 4, 7, 11, 16, 22, 29, 37]
print([R(3, n) for n in range(0, 9)])# [1, 2, 4, 8, 15, 26, 42, 64, 93]
print([1 + comb(n, 2) + comb(n, 4) for n in range(1, 9)])       # Moser : 31, pas 32# [1, 2, 4, 8, 16, 31, 57, 99]
print([2**(n-1) for n in range(1, 9)])# [1, 2, 4, 8, 16, 32, 64, 128]
L·66théorème de Dirichlet sur les progressions arithmétiques
\(\#\{p\leq N\ \text{premier} : p\equiv a\ (\mathrm{mod}\ q)\}\)
\(\sim\)
\(\dfrac{1}{\varphi(q)}\,\dfrac{N}{\ln N}\)

pour tout \(a\) premier avec \(q\), quand \(N\to\infty\). Dirichlet (1837) a prouvé que chaque progression \(a,\ a+q,\ a+2q,\dots\) contient une infinité de premiers, en inventant pour cela ses fonctions \(L\) ; de la Vallée Poussin (1896) a montré qu'elles se partagent les premiers à parts égales, \(1/\varphi(q)\) chacune. Exemple avec \(q=9\) : les six suites qui partent de 1, 2, 4, 5, 7, 8 (et avancent de 9 en 9) reçoivent chacune un sixième des premiers. Attention au sens : c'est \(N/\ln N\), pas \(N\ln N\). Finesse célèbre, le biais de Chebyshev (1853) : les classes qui ne sont pas des carrés modulo \(q\) mènent presque toujours la course. Modulo 4, la classe de 3 devance celle de 1 jusqu'à 26 861, et Rubinstein et Sarnak (1994) ont estimé, sous des hypothèses de type Riemann, qu'elle mène environ 99,6 % du « temps » logarithmique.

sorte loifamille nombres premiers
# les six classes modulo 9 jusqu'à 10⁷ ; leur part ; le biais de Chebyshev ; puis la course modulo 4
import math
N = 10**7
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, int(N**0.5)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
compte = {r: 0 for r in (1, 2, 4, 5, 7, 8)}
for n in range(2, N+1):
    if crible[n] and n % 9 in compte: compte[n % 9] += 1
print(compte)                 # {1: 110772, 2: 110836, 4: 110743, 5: 110760, 7: 110679, 8: 110788}
print(sum(compte.values()) // 6, round(N / math.log(N) / 6))# 110763 103403
print(compte[2] + compte[5] + compte[8], compte[1] + compte[4] + compte[7])   # biais : non-carrés devant# 332384 332194
c1 = c3 = 0
for n in range(3, N+1):                         # la course modulo 4
    if crible[n]:
        if n % 4 == 1: c1 += 1
        else: c3 += 1
        if c1 > c3: break
print(n)                      # 26861
L·67les polynômes cyclotomiques
\(x^{n}-1\)
=
\(\prod_{d\mid n}\Phi_d(x)\)

où \(\Phi_d\) a pour racines les racines \(d\)-ièmes primitives de l'unité (L·52), et pour degré \(\varphi(d)\). Les racines \(n\)-ièmes de \(-1\), \((-1)^{1/n}=e^{i\pi/n}\), sont des racines de \(\Phi_{2n}\) : \(\Phi_4=x^{2}+1\), \(\Phi_6=x^{2}-x+1\), \(\Phi_8=x^{4}+1\), \(\Phi_{10}=x^{4}-x^{3}+x^{2}-x+1\), \(\Phi_{12}=x^{4}-x^{2}+1\), \(\Phi_{14}=x^{6}-x^{5}+\dots+1\). Le coefficient juste sous le terme de tête vaut \(-\mu(n)\), puisque la somme des racines est \(\mu(n)\) (L·52). Tous les coefficients valent 0, 1 ou −1… jusqu'à \(\Phi_{105}\), qui contient un −2 (Migotti, 1883) ; ensuite, ils deviennent aussi grands qu'on veut. Encore un motif qui trompe (voir Moser, L·65).

sorte loifamille exponentielle complexe ; fonctions arithmétiques
# tous les Φₙ jusqu'à 210 par division exacte ; tes exemples ; le degré φ(n) et le coefficient −μ(n) ; puis le −2 de Φ₁₀₅
from math import gcd
def divise(a, b):                              # division exacte de polynômes entiers (degrés décroissants)
    a, q = a[:], []
    while len(a) >= len(b):
        c = a[0] // b[0]; q.append(c)
        for i in range(len(b)): a[i] -= c * b[i]
        a.pop(0)
    return q
def produit(a, b):
    r = [0]*(len(a) + len(b) - 1)
    for i, x in enumerate(a):
        for j, y in enumerate(b): r[i+j] += x*y
    return r
Phi = {}
for n in range(1, 211):
    P = [1] + [0]*(n-1) + [-1]                  # xⁿ − 1
    for d in range(1, n):
        if n % d == 0: P = divise(P, Phi[d])
    Phi[n] = P
ok = True
for n in range(1, 211):
    P = [1]
    for d in range(1, n+1):
        if n % d == 0: P = produit(P, Phi[d])
    ok &= P == [1] + [0]*(n-1) + [-1]
print(ok)                     # True
print({n: Phi[n] for n in (6, 10, 12, 14)})# {6: [1, -1, 1], 10: [1, -1, 1, -1, 1], 12: [1, 0, -1, 0, 1], 14: [1, -1, 1, -1, 1, -1, 1]}
phi = lambda n: sum(1 for k in range(1, n+1) if gcd(k, n) == 1)
def mu(n):
    r, m, q = 1, n, 2
    while q*q <= m:
        if m % q == 0:
            m //= q
            if m % q == 0: return 0
            r = -r
        q += 1
    return -r if m > 1 else r
print(all(len(Phi[n]) - 1 == phi(n) for n in range(1, 211)),# True True
      all(Phi[n][1] == -mu(n) for n in range(2, 211)))
print(max(max(abs(c) for c in Phi[n]) for n in range(1, 105)), min(Phi[105]))# 1 -2
L·68la borne inférieure des tris par comparaisons
\(C(n)\)
\(\geq\)
\(\bigl\lceil\log_2 n!\bigr\rceil\approx n\log_2n-1{,}44\,n\)

où \(C(n)\) est le nombre minimal de comparaisons qu'il faut, dans le pire des cas, pour trier \(n\) objets en les comparant deux à deux. Argument : il y a \(n!\) ordres possibles, et chaque comparaison, qui répond oui ou non, divise au mieux les possibilités par deux ; il en faut donc au moins \(\log_2 n!\). Stirling (X·5) donne \(\log_2 n!\approx n\log_2 n-n\log_2 e\), d'où le « \(n\ln n\) » de l'informatique, à un facteur constant près : c'est \(\log_2\) qui compte. L'algorithme de Ford et Johnson (1959) atteint la borne jusqu'à 11 objets ; pour 12 objets, la borne vaut 29 comparaisons, mais il en faut réellement 30 (Wells, 1965, par recherche sur ordinateur).

sorte loifamille comptage
# la borne et Ford–Johnson (29 contre 30 pour n = 12) ; le pire cas du tri fusion sur toutes les permutations ; puis Stirling
from math import factorial, log2, ceil, e
from itertools import permutations
borne = lambda n: ceil(log2(factorial(n)))
FJ = lambda n: sum(ceil(log2(3*k/4)) for k in range(1, n+1))      # Ford–Johnson, pire cas
print([borne(n) for n in range(1, 13)])# [0, 1, 3, 5, 7, 10, 13, 16, 19, 22, 26, 29]
print([FJ(n) for n in range(1, 13)])# [0, 1, 3, 5, 7, 10, 13, 16, 19, 22, 26, 30]
def tri_fusion(L, c):                          # tri fusion qui compte ses comparaisons
    if len(L) <= 1: return L
    a, b = tri_fusion(L[:len(L)//2], c), tri_fusion(L[len(L)//2:], c)
    r = []
    while a and b:
        c[0] += 1
        r.append(a.pop(0) if a[0] < b[0] else b.pop(0))
    return r + a + b
def pire_fusion(n):
    pire = 0
    for P in permutations(range(n)):
        c = [0]; tri_fusion(list(P), c); pire = max(pire, c[0])
    return pire
print([pire_fusion(n) for n in range(1, 9)], [borne(n) for n in range(1, 9)])# [0, 1, 3, 5, 8, 11, 14, 17] [0, 1, 3, 5, 7, 10, 13, 16]
n = 10**6
print(round(log2(factorial(20)), 3), round(20*log2(20) - 20*log2(e) + 0.5*log2(2*3.141592653589793*20), 3))# 61.077 61.071
L·69l'inégalité arithmético-géométrique
\(\dfrac{x_1+x_2+\dots+x_n}{n}\)
\(\geq\)
\(\sqrt[n]{x_1x_2\cdots x_n}\)

pour tous réels \(x_i\geq0\), avec égalité seulement quand ils sont tous égaux. Pour deux nombres, c'est \((\sqrt x-\sqrt y)^{2}\geq0\) ; Cauchy (1821) l'a étendue à \(n\) nombres par une récurrence qui double puis redescend, et on peut aussi la tirer de la concavité du logarithme. Elle s'inscrit dans une chaîne : moyenne harmonique \(\leq\) géométrique \(\leq\) arithmétique \(\leq\) quadratique. Sens géométrique : à périmètre égal, le carré est le rectangle d'aire maximale (et le cube, la boîte de volume maximal), cousin en polygones de l'inégalité isopérimétrique \(4\pi A\leq P^{2}\), où c'est le cercle qui gagne.

sorte loifamille opérations
# 20 000 listes au hasard pour la chaîne H ≤ G ≤ A ≤ Q ; le cas d'égalité ; puis les rectangles de périmètre 4
import random, math
random.seed(1)
ok_chaine, ecart_min = True, 1.0
for _ in range(20000):
    n = random.randint(2, 20)
    x = [random.uniform(0.001, 100) for _ in range(n)]
    H = n / sum(1/t for t in x)
    G = math.exp(sum(math.log(t) for t in x) / n)
    A = sum(x) / n
    Q = math.sqrt(sum(t*t for t in x) / n)
    ok_chaine &= H <= G*(1 + 1e-12) and G <= A*(1 + 1e-12) and A <= Q*(1 + 1e-12)
print(ok_chaine)              # True
x = [7.5]*9                                    # égalité : tous égaux
print(sum(x)/9, math.prod(x)**(1/9))# 7.5 7.499999999999999
aires = [(a, round(a*(2 - a), 4)) for a in (0.2, 0.6, 1.0, 1.4, 1.8)]   # périmètre 4
print(aires)                  # [(0.2, 0.36), (0.6, 0.84), (1.0, 1.0), (1.4, 0.84), (1.8, 0.36)]
L·70la formule explicite de Riemann
\(\pi_0(x)\)
=
\(R(x)-\sum_{\rho}R(x^{\rho})-\frac{1}{\ln x}+\frac1\pi\arctan\frac{\pi}{\ln x}\)

pour \(x>1\), avec la fonction \(R\) de Riemann, \(R(x)=\sum_{n\geq1}\dfrac{\mu(n)}{n}\operatorname{li}\bigl(x^{1/n}\bigr)\). La somme porte sur les zéros non triviaux \(\rho\) de \(\zeta\), groupés par paires conjuguées ; les deux derniers termes sont la contribution des zéros triviaux. \(\pi_0\) compte les premiers jusqu'à \(x\), en prenant la moyenne aux sauts. Riemann (1859) l'a écrite, von Mangoldt (1895) l'a démontrée. Chaque zéro ajoute une vague qui redessine l'escalier des premiers. À lui seul, \(R\) approche déjà \(\pi\) bien mieux que \(\operatorname{li}\) (L·32) : pour \(x=10^{6}\), \(R\) donne 78 527,4 et \(\operatorname{li}\) 78 627,5, pour 78 498 premiers. L'hypothèse de Riemann (C·2) revient à dire que toutes ces vagues restent de taille \(\sqrt x\).

sorte loifamille nombres premiers ; valeurs de ζ
# π, R et li à un million ; puis la formule en x = 100 avec 0, 10, 50, 100 et 200 zéros : elle converge vers 25 en oscillant
from mpmath import mp, mpf, riemannr, li, ei, log, re, quad, inf, zetazero, nstr
import math
mp.dps = 20
N = 10**6
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, int(N**0.5)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
print(sum(crible), nstr(riemannr(N), 9), nstr(li(N), 9))# 78498 78527.3994 78627.5492
def mu(n):
    r, m, q = 1, n, 2
    while q*q <= m:
        if m % q == 0:
            m //= q
            if m % q == 0: return 0
            r = -r
        q += 1
    return -r if m > 1 else r
# même formule, regroupée sous sa forme finie : π₀(x) = Σ_{n ≤ log₂ x} μ(n)/n · J(x^(1/n)), avec
# J(y) = li(y) − Σ_ρ li(y^ρ) − ln 2 + ∫_y^∞ dt / (t(t²−1) ln t), et li(y^ρ) = Ei(ρ ln y)
Z = [zetazero(k) for k in range(1, 201)]
def J(y, K):
    return (li(y) - sum(2*re(ei(r*log(y))) for r in Z[:K]) - log(2)
            + quad(lambda t: 1/(t*(t*t - 1)*log(t)), [y, inf]))
x = mpf(100)                                   # π(100) = 25, et 100 n'est pas premier
pi0 = lambda K: sum(mu(n)/mpf(n) * J(x**(mpf(1)/n), K) for n in range(1, int(math.log2(100))+1) if mu(n))
print([nstr(pi0(K), 6) for K in (0, 10, 50, 100, 200)])# ['25.6885', '25.2813', '25.0775', '24.9147', '24.9256']
L·71la formule explicite de von Mangoldt pour ψ
\(\psi(x)\)
=
\(x-\sum_{\rho}\frac{x^{\rho}}{\rho}-\ln(2\pi)-\tfrac12\ln\bigl(1-x^{-2}\bigr)\)

pour \(x>1\) qui n'est pas une puissance de premier (von Mangoldt, 1895), où \(\psi(x)=\sum_{n\leq x}\Lambda(n)=\ln\operatorname{ppcm}(1,\dots,\lfloor x\rfloor)\) (VIII·3) et où \(\rho\) parcourt les zéros non triviaux de \(\zeta\), par paires conjuguées. Le graphe de \(\psi\) est un escalier qui épouse la droite \(y=x\), et les zéros y ajoutent des vagues. Il saute de \(\ln p\) à chaque puissance de premier, donc aussi en 4, 8, 9, 16, 25, 27… ; c'est \(\theta(x)=\sum_{p\leq x}\ln p\) qui ne saute qu'aux premiers, tandis que \(\pi(x)\) saute de 1 et suit la courbe \(x/\ln x\). D'où vient la formule : une série de Dirichlet est une transformée intégrale de son escalier, \(\displaystyle-\frac{\zeta'(s)}{\zeta(s)}=\sum\frac{\Lambda(n)}{n^{s}}=s\int_1^{\infty}\psi(x)\,x^{-s-1}\,dx\) (une intégrale de Stieltjes, qui devient une transformée de Laplace avec \(x=e^{u}\)) ; on l'inverse par la formule de Perron, et les pôles de \(-\zeta'/\zeta\), c'est-à-dire les zéros de \(\zeta\), donnent les termes de la somme.

sorte loifamille nombres premiers ; valeurs de ζ
# les sauts de ψ ; la formule en x = 100,5 avec 0 à 300 zéros ; puis série de Dirichlet = intégrale de l'escalier
from math import lcm, log
from functools import reduce
from mpmath import mp, mpf, zetazero, zeta, pi, re, nstr
mp.dps = 20
def Lam(n):                                    # von Mangoldt (L·30)
    for q in range(2, n+1):
        if n % q == 0:
            while n % q == 0: n //= q
            return log(q) if n == 1 else 0.0
    return 0.0
print([(n, round(Lam(n), 3)) for n in range(2, 30) if Lam(n)])   # les sauts : puissances de premiers# [(2, 0.693), (3, 1.099), (4, 0.693), (5, 1.609), (7, 1.946), (8, 0.693), (9, 1.099), (11, 2.398), (13, 2.565), (16, 0.693), (17, 2.833), (19, 2.944), (23, 3.135), (25, 1.609), (27, 1.099), (29, 3.367)]
x = mpf('100.5')
psi = log(reduce(lcm, range(1, 101)))
Z = [zetazero(k) for k in range(1, 301)]
f = lambda K: x - sum(2*re(x**r / r) for r in Z[:K]) - log(2*pi) - log(1 - x**-2)/2
print(round(psi, 6), [nstr(f(K), 7) for K in (0, 10, 100, 300)])# 94.045311 ['98.66217', '95.77622', '95.00926', '93.78253']
N, s = 20000, 2                                # le pont Dirichlet ↔ intégrale (sommation d'Abel)
L = [0.0] + [Lam(n) for n in range(1, N+1)]
ps = [0.0]*(N+1)
for n in range(1, N+1): ps[n] = ps[n-1] + L[n]
integrale = sum(ps[k] * (k**-s - (k+1)**-s) / s for k in range(1, N))   # ∫₁ᴺ ψ(x) x^(−s−1) dx, exacte
print(round(s*integrale + ps[N]*N**-s, 12), round(sum(L[n]*n**-s for n in range(1, N+1)), 12))# 0.569910938076 0.569910938076
print(nstr(-zeta(s, derivative=1)/zeta(s), 10))# 0.5699609931
L·72la pile de cartes qui déborde
\(\text{débordement}(n)\)
=
\(\tfrac12H_n=\tfrac12\Bigl(1+\tfrac12+\tfrac13+\dots+\tfrac1n\Bigr)\)

en longueurs de carte, pour \(n\) cartes empilées au bord d'une table, une par étage, chacune décalée au maximum sans que la pile tombe. En partant du haut, la \(k\)-ième carte dépasse de \(\tfrac1{2k}\) celle du dessous : le centre de gravité des \(k\) cartes du haut tombe alors pile sur le bord de la carte suivante, et celui de toute la pile sur le bord de la table. Avec 100 cartes, \(\tfrac12H_{100}\approx2{,}59\) longueurs dans le vide. Comme \(H_n\) tend vers l'infini (L·37 et XI·2), on peut déborder aussi loin qu'on veut, mais chaque longueur supplémentaire coûte environ \(e^{2}\approx7{,}4\) fois plus de cartes, puisque \(\tfrac12H_n\approx\tfrac12(\ln n+\gamma)\). Au passage, \(H_{10n}-H_n\) tend vers \(\ln10\approx2{,}3026\), l'écart entre deux puissances de 10. En s'autorisant plusieurs cartes par étage, on fait bien mieux : un débordement qui grandit comme \(n^{1/3}\) (Paterson et Zwick, 2006).

débordementcartes nécessaires
1 longueur4
2 longueurs31
3 longueurs227
4 longueurs1 674
5 longueurs12 367
6 longueurs91 380
sorte loifamille nombres harmoniques
# l'équilibre exact de chaque étage (en fractions) ; les 100 cartes ; le tableau et son rapport e² ; puis tes valeurs de Hₙ et l'écart ln 10
from fractions import Fraction as Fr
from mpmath import mp, mpf, harmonic, log, e, nstr
def pile(n):                                   # bords droits, du haut vers le bas ; table en x = 0
    R = [sum(Fr(1, 2*k) for k in range(j, n+1)) for j in range(1, n+1)] + [Fr(0)]
    centres = [r - Fr(1, 2) for r in R[:n]]
    equilibre = all(sum(centres[:j]) / j == R[j] for j in range(1, n+1))   # centre de gravité sur le bord
    return R[0], equilibre
print(all(pile(n)[1] for n in range(1, 60)))# True
print(pile(100)[0] == sum(Fr(1, 2*k) for k in range(1, 101)), float(pile(100)[0]))# True 2.5936887588198103
H, n, besoin, cible = 0.0, 0, [], 1
while len(besoin) < 6:
    n += 1; H += 1/n
    if H/2 >= cible: besoin.append(n); cible += 1
print(besoin, [round(besoin[i+1]/besoin[i], 2) for i in range(5)], round(float(e**2), 2))# [4, 31, 227, 1674, 12367, 91380] [7.75, 7.32, 7.37, 7.39, 7.39] 7.39
mp.dps = 20
print([nstr(harmonic(10**k), 11) for k in range(1, 10)])# ['2.928968254', '5.1873775176', '7.4854708606', '9.787606036', '12.09014613', '14.392726723', '16.695311366', '18.997896414', '21.300481502']
print(nstr(harmonic(10**9) - harmonic(10**8), 10), nstr(log(10), 10))# 2.302585088 2.302585093

CConjectures

C·1problème de Lehmerouvert depuis 1932
\(\varphi(n)\mid n-1\)
\(\overset{?}{\Longrightarrow}\)
\(n\ \text{premier}\)

pour \(n\geq2\) ; autrement dit, \(n\equiv1 \pmod{\varphi(n)}\) suffirait-il à rendre \(n\) premier ? La réciproque est vraie, car \(\varphi(p)=p-1\). On ne connaît aucun contre-exemple, et on sait qu'il en faudrait un énorme, avec beaucoup de facteurs premiers.

sorte conjecturefamille indicatrice φ
# une recherche n'est pas une preuve : aucun contre-exemple sous 10⁶
N = 10**6
phi = list(range(N+1))
for p in range(2, N+1):
    if phi[p] == p:
        for m in range(p, N+1, p):
            phi[m] -= phi[m] // p
contre = [n for n in range(2, N+1)
          if (n-1) % phi[n] == 0 and phi[n] != n-1]
print(contre)             # []
C·2hypothèse de Riemannouvert depuis 1859
\(\zeta(s)=0,\ \ 0<\operatorname{Re}s<1\)
\(\overset{?}{\Longrightarrow}\)
\(\operatorname{Re}s=\tfrac12\)

tous les zéros non triviaux de ζ seraient sur la droite critique. C'est le centre de la symétrie de L·20 : l'équation fonctionnelle place les zéros en miroir autour de \(\operatorname{Re}s=\tfrac12\), l'hypothèse dit qu'ils sont tous sur le miroir lui-même. Vérifiée par le calcul pour des milliers de milliards de zéros, jamais démontrée ; l'un des problèmes du millénaire.

sorte conjecturefamille valeurs de ζ ; fonction Γ
# méthode de Turing : on compte les zéros dans toute la bande critique,
# puis ceux qui sont sur la droite ; s'il y en a autant, aucun n'est ailleurs.
# Une vérification finie n'est pas une preuve.
from mpmath import mp, nzeros, zetazero
mp.dps = 25
T = 100
# zéros dans la bande 0 < Re s < 1, 0 < Im s ≤ T
print(nzeros(T))            # 29
# zéros trouvés sur la droite Re s = ½
k = 0
while zetazero(k+1).imag <= T: k += 1
print(k)                    # 29
print(zetazero(1))          # (0.5 + 14.13472514173469379045725j)
C·3l'empilement optimal en dimension 4ouvert
\(\Delta_4\)
\(\overset{?}{=}\)
\(\dfrac{\pi^{2}}{16}\)

on sait l'empilement optimal en dimensions 1, 2, 3, 8 et 24 seulement ; la dimension 4 est la première inconnue. Le meilleur candidat est le réseau \(D_4\) (points entiers de somme paire) : parmi les empilements en réseau, il est prouvé optimal depuis Korkine et Zolotarev (1877), et chaque boule y touche 24 voisines, le maximum possible en dimension 4 (Musin, 2008). Ces 24 voisines sont les sommets du 24-cellules, le solide de Platon propre à la dimension 4. Reste à exclure tout empilement irrégulier plus dense : c'est ouvert.

dim.densité optimaledémontrée par
1\(1\)évident
2\(\pi/(2\sqrt3)\approx0{,}9069\)Thue, puis Fejes Tóth (1940)
3\(\pi/(3\sqrt2)\approx0{,}7405\)Kepler (1611) ; Hales (2005), preuve formelle en 2017
4\(\pi^{2}/16\approx0{,}6169\) ?ouvert
8\(\pi^{4}/384\approx0{,}2537\)Viazovska (2016), L·21
24\(\pi^{12}/12!\approx0{,}0019\)Cohn et al. (2016), L·23
sources

A. Korkine et G. Zolotareff, « Sur les formes quadratiques positives », Mathematische Annalen 11 (1877).

O. R. Musin, « The kissing number in four dimensions », Annals of Mathematics 168 (2008).

sorte conjecturefamille empilements ; boules et sphères
# voisines et densité de D4 ; l'optimalité parmi tous les empilements reste à prouver
from itertools import product
from mpmath import mp, mpf, pi, gamma, sqrt
mp.dps = 25
V = lambda n, r=1: pi**(mpf(n)/2) / gamma(mpf(n)/2 + 1) * r**n    # L·10
# D4 : vecteurs entiers de somme paire, covolume 2, distance minimale √2
voisins = [v for v in product(range(-1, 2), repeat=4)
           if sum(x*x for x in v) == 2 and sum(v) % 2 == 0]
print(len(voisins))           # 24
print(V(4, 1/sqrt(2)) / 2)    # 0.6168502750680849136771557
print(pi**2/16)               # 0.6168502750680849136771557
C·4conjecture d'Eswarathasan et Levineouvert depuis 1991
\(\#\{\,n : p\mid\operatorname{num}H_n\}\)
\(\overset{?}{<}\)
\(\infty\)

pour tout premier \(p\), l'ensemble des \(n\) où \(p\) divise le numérateur de \(H_n\) serait fini. Pour \(p=2\) il est vide (L·37) ; pour \(p=3\), c'est \(\{2,7,22\}\) ; pour \(p=5\), \(\{4,20,24\}\) ; pour \(p=7\), il s'allonge déjà. Ces ensembles commandent la suite A110566, \(\operatorname{PPCM}(1,\dots,n)\) divisé par le dénominateur de \(H_n\) : 1, 1, 1, 1, 1, 3, 3, 3… Un premier \(p\) la divise exactement quand \(\lfloor n/p^{k}\rfloor\) tombe dans l'ensemble de \(p\), où \(p^{k}\) est la plus grande puissance de \(p\) qui ne dépasse pas \(n\). Pour \(n=6\) : \(\lfloor6/3\rfloor=2\), qui est dans l'ensemble de 3 ; de fait, \(\tfrac13+\tfrac16=\tfrac12\), et le 3 disparaît du dénominateur.

sources

A. Eswarathasan et E. Levine, « p-integral harmonic sums », 1991.

sorte conjecturefamille nombres harmoniques
# les ensembles pour p = 2, 3, 5, 7 jusqu'à 600 ; A110566 ; puis la règle qui la relie aux ensembles
from fractions import Fraction
from math import lcm
N = 600
H, L = [Fraction(0)], [1]
for n in range(1, N+1):
    H.append(H[-1] + Fraction(1, n)); L.append(lcm(L[-1], n))
J = lambda p: [n for n in range(1, N+1) if H[n].numerator % p == 0]
print(J(2))                   # []
print(J(3))                   # [2, 7, 22]
print(J(5))                   # [4, 20, 24]
print(J(7))                   # [6, 42, 48, 295, 299, 337, 341]
print([L[n] // H[n].denominator for n in range(1, 25)])    # A110566# [1, 1, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 15, 45, 45, 45, 15]
premiers = [p for p in range(2, N+1) if all(p % q for q in range(2, int(p**0.5)+1))]
Js = {p: set(J(p)) for p in premiers}
def prevu(n):                                  # premiers p avec ⌊n/p^k⌋ dans J(p)
    out = set()
    for p in premiers:
        if p > n: break
        k = 1
        while p**(k+1) <= n: k += 1
        if n // p**k in Js[p]: out.add(p)
    return out
print(all({p for p in premiers if (L[n] // H[n].denominator) % p == 0} == prevu(n)# True
          for n in range(1, N+1)))
C·5les nombres premiers suivent une loi de Poissonouvert (sous condition)
\(\#\{\text{premiers dans }[x,\;x+\lambda\ln x]\}\)
\(\overset{?}{\sim}\)
\(\text{Poisson}(\lambda)\)

quand \(x\to\infty\), pour \(\lambda\) fixé. L'idée vient du modèle aléatoire de Cramér (1936) : faire comme si chaque entier \(n\) était premier avec probabilité \(1/\ln n\), comme des déchirures dans un tissu (L·56). Gallagher (1976) a démontré cette loi de Poisson à condition que la conjecture des \(k\)-uplets premiers de Hardy et Littlewood soit vraie, ce qui reste ouvert. Deux précautions : la densité des premiers près de \(x\) est \(1/\ln x\), avec le logarithme naturel (avec \(\log_{10}\), on en prédirait 2,3 fois trop) ; et il faut des intervalles de longueur proportionnelle à \(\ln x\), car un intervalle de longueur 1 ne contient qu'un seul entier. Le modèle de Cramér a ses limites : Maier (1985) a montré qu'il se trompe sur des intervalles un peu plus longs. Et à portée de calcul, les premiers sont plus réguliers que le hasard, puisqu'ils évitent les multiples de 2, 3, 5…

sources

H. Cramér, « On the order of magnitude of the difference between consecutive prime numbers », Acta Arithmetica 2 (1936).

P. X. Gallagher, « On the distribution of primes in short intervals », Mathematika 23 (1976).

sorte conjecturefamille nombres premiers ; probabilités
# premiers près d'un million contre les deux densités ; puis les répartitions observées près de 10⁷ contre Poisson
import math
from collections import Counter
N = 2 * 10**7
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, int(N**0.5)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
x, w = 10**6, 10**4                            # la bonne densité : 1/ln x
print(sum(crible[x:x+w]), round(w/math.log(x)), round(w/math.log10(x)))# 753 724 1667
x0 = 10**7
def compare(h):                               # (observé, Poisson) pour k = 0 … 5
    C = Counter(sum(crible[a:a+h]) for a in range(x0, x0 + 5*10**6, h))
    tot, lam = sum(C.values()), h / math.log(x0)
    return [(round(C[k]/tot, 3), round(math.exp(-lam)*lam**k/math.factorial(k), 3)) for k in range(6)]
print(compare(16))                             # λ ≈ 1# [(0.322, 0.371), (0.428, 0.368), (0.202, 0.183), (0.043, 0.06), (0.004, 0.015), (0.0, 0.003)]
print(compare(48))                             # λ ≈ 3# [(0.027, 0.051), (0.125, 0.152), (0.243, 0.226), (0.275, 0.224), (0.195, 0.167), (0.096, 0.099)]
Aucune fiche ne réunit ces critères.