← nimbers
175 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
I·5le caractère modulo 12
\(\displaystyle\sum_{k=0}^{\infty}\Bigl(\frac1{12k+1}-\frac1{12k+5}-\frac1{12k+7}+\frac1{12k+11}\Bigr)\)
=
\(\dfrac{\ln\!\left(2+\sqrt{3}\right)}{\sqrt{3}}\)

c'est \(L(1,\chi_{12})=1-\frac15-\frac17+\frac1{11}+\frac1{13}-\frac1{17}-\frac1{19}+\cdots\), avec le caractère \(\chi_{12}\) qui vaut \(+1\) sur 1 et 11 modulo 12, et \(-1\) sur 5 et 7 (L·94). Leibniz (I·2) est la même construction avec \(\chi_4\). La forme close vient de la formule du nombre de classes de Dirichlet (1839) : pour un caractère réel pair de conducteur \(D\), \(L(1,\chi)=\frac{2h\,\ln\varepsilon}{\sqrt D}\), où \(h\) est le nombre de classes du corps \(\mathbb Q(\sqrt3)\) et \(\varepsilon\) son unité fondamentale. Ici \(D=12\), \(h=1\), et \(\varepsilon=2+\sqrt3\), qui vérifie \((2+\sqrt3)(2-\sqrt3)=1\). On la retrouve aussi par la fonction digamma, comme les autres perles de la série : \(\frac1{12}\bigl[\psi(\frac5{12})+\psi(\frac7{12})-\psi(\frac1{12})-\psi(\frac{11}{12})\bigr]\).

const mixte ln(2+√3) & √3type sériefamille caractère de Dirichlet mod 12
# mpmath, 25 chiffres ; la route digamma ; puis l'unité fondamentale et la formule du nombre de classes
from mpmath import mp, mpf, nsum, inf, log, sqrt, digamma, nstr
mp.dps = 25
s = nsum(lambda k: 1/(12*k+1) - 1/(12*k+5) - 1/(12*k+7) + 1/(12*k+11), [0, inf])
print(s)                      # 0.7603459963009463475310942
print(log(2 + sqrt(3)) / sqrt(3))# 0.7603459963009463475310942
print(nstr((digamma(mpf(5)/12) + digamma(mpf(7)/12) - digamma(mpf(1)/12) - digamma(mpf(11)/12))/12 - s, 3))# 0.0
print((2 + sqrt(3)) * (2 - sqrt(3)), nstr(2 * 1 * log(2 + sqrt(3)) / sqrt(12) - s, 3))# 1.0 0.0
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}\). Écrit facteur par facteur, \(1-\frac1{p^{2}}=\frac{(p-1)(p+1)}{p^{2}}\), on obtient \(\frac34\cdot\frac89\cdot\frac{24}{25}\cdot\frac{48}{49}\cdots\) : les dénominateurs sont les carrés de premiers (A001248), et les numérateurs \(p^{2}-1\) (A084920). Attention au sens : c'est ce produit qui tend vers \(6/\pi^{2}\), et son inverse vers \(\pi^{2}/6\).

const πtype produitfamille valeurs de ζ ; nombres premiers
# produits partiels jusqu'à 10², 10⁴, 10⁶ ; puis le produit complet, par la zêta des premiers ; enfin les suites A001248 et A084920, et le produit inverse vers 6/π²
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
print([q*q for q in premiers[:6]], [(q - 1)*(q + 1) for q in premiers[:6]], nstr(1/partiel(10**6), 8), nstr(6/pi**2, 8))# [4, 9, 25, 49, 121, 169] [3, 8, 24, 48, 120, 168] 0.60792714 0.6079271
II·7l'intégrale de Planck
\(\displaystyle\int_0^{\infty}\frac{x^{3}}{e^{x}-1}\,dx\)
=
\(\dfrac{\pi^{4}}{15}\)

c'est \(\Gamma(4)\,\zeta(4)=6\cdot\frac{\pi^{4}}{90}\), un cas de l'intégrale de Riemann (L·78). L'histoire vient de la lumière : chaque atome a sa signature, son spectre de raies d'absorption et d'émission, et un corps chauffé rayonne selon la loi de Planck (1900), \(u(\nu)=\frac{8\pi\nu^{2}}{c^{3}}\cdot\frac{h\nu}{e^{h\nu/kT}-1}\). Avec \(x=h\nu/kT\), tout se ramène à \(\frac{x}{e^{x}-1}\), la fonction génératrice des nombres de Bernoulli (L·51). Intégrer sur toutes les fréquences donne l'énergie totale, proportionnelle à \(T^{4}\) avec ce facteur \(\pi^{4}/15\) : c'est la loi de Stefan–Boltzmann, dont la constante \(\sigma=\frac{2\pi^{5}k^{4}}{15c^{2}h^{3}}\) se calcule ainsi à partir de \(h\), \(k\) et \(c\). Pour les raies des atomes, le principe de combinaison de Ritz (1908) dit que les fréquences s'additionnent en chaîne, \(\nu_{\alpha\beta}+\nu_{\beta\gamma}=\nu_{\alpha\gamma}\), l'ordre des indices comptant ; c'est cette règle qui a guidé Heisenberg vers sa mécanique des matrices (1925).

const πtype intégralefamille valeurs de ζ ; fonction Γ
# l'intégrale à 25 chiffres, π⁴/15, Γ(4)ζ(4) et la série ; puis σ de Stefan–Boltzmann
from mpmath import mp, quad, exp, inf, pi, gamma, zeta, nsum
mp.dps = 25
print(quad(lambda x: x**3 / (exp(x) - 1), [0, inf]))# 6.493939402266829149096022
print(pi**4 / 15)             # 6.493939402266829149096022
print(gamma(4) * zeta(4))     # 6.493939402266829149096022
print(nsum(lambda n: 6 / n**4, [1, inf]))      # 1/(eˣ−1) = Σ e^(−nx), et ∫ x³ e^(−nx) dx = 6/n⁴# 6.493939402266829149096022
h, k, c = 6.62607015e-34, 1.380649e-23, 299792458   # valeurs exactes du SI
print(2 * pi**5 * k**4 / (15 * c**2 * h**3))   # constante de Stefan–Boltzmann, en W/m²/K⁴# 5.670374419184431234209388e-8
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
IV·4produit de Woods–Robbins
\(\displaystyle\prod_{n=0}^{\infty}\Bigl(\frac{2n+1}{2n+2}\Bigr)^{t(n)}=\frac12\cdot\frac{\;\frac12\;}{\frac34}\Bigg/\frac{\;\frac56\;}{\frac78}\cdots\)
=
\(\dfrac{\sqrt{2}}{2}\)

où \(t(n)=\pm1\) suit la suite de Thue–Morse (L·100) : 1, −1, −1, 1, −1, 1, 1, −1… (Woods, 1978 ; Robbins, 1979). La preuve tient en quelques lignes. On pose \(P\) ce produit et \(Q=\prod_{n\geq1}\bigl(\frac{2n}{2n+1}\bigr)^{t(n)}\). En multipliant, \(P\,Q=\frac12\prod_{n\geq1}\bigl(\frac{n}{n+1}\bigr)^{t(n)}\). On sépare ensuite les \(n\) pairs et impairs grâce à \(t(2n)=t(n)\) et \(t(2n+1)=-t(n)\) : il reste \(P\,Q=\frac12\cdot\frac{Q}{P}\), d'où \(P^{2}=\frac12\). Le produit converge, mais pas facteur par facteur. Il faut le prendre par blocs de \(2^{K}\) facteurs, et il converge alors à une vitesse stupéfiante : \(10^{-11}\) d'erreur avec 256 facteurs, \(10^{-35}\) avec 65 536. Personne ne connaît en revanche de forme close pour \(Q\).

const √2type produit infinifamille Thue–Morse
# le produit par blocs de 2¹⁶ facteurs ; la vitesse de convergence ; puis la relation PQ = Q/(2P) de la preuve
from mpmath import mp, mpf, log, exp, sqrt, fsum, nstr
mp.dps = 40
t = lambda n: 1 - 2*(bin(n).count('1') % 2)
P = lambda K: exp(fsum(t(n) * log(mpf(2*n + 1)/(2*n + 2)) for n in range(2**K)))
Q = lambda K: exp(fsum(t(n) * log(mpf(2*n)/(2*n + 1)) for n in range(1, 2**K)))
print(nstr(P(16), 25))        # 0.7071067811865475244008444
print(nstr(sqrt(2)/2, 25))    # 0.7071067811865475244008444
print([nstr(P(K) - 1/sqrt(2), 3) for K in (4, 8, 12, 16)])# ['-8.28e-5', '-3.75e-11', '-2.19e-21', '-8.26e-36']
print(nstr(P(16) * Q(16) - Q(16) / (2 * P(16)), 3), nstr(Q(16), 15))# -2.69e-35 1.62816012971892
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. Un cube familier : celui des couleurs RGB, \(\{0,255\}^{3}\). Ses huit sommets sont le noir (0, 0, 0), le rouge, le vert, le bleu, le jaune (255, 255, 0), le cyan, le magenta et le blanc (255, 255, 255). La grande diagonale du noir au blanc porte les gris. La couleur complémentaire d'un sommet est le sommet opposé \((255-r,\,255-g,\,255-b)\). Le centre \((127{,}5\,;\,127{,}5\,;\,127{,}5)\) n'est pas une couleur codable : en pratique, on prend 127 ou 128.

sorte loifamille hypercubes
# énumération exhaustive de toutes les faces, n = 1 à 8 (la dernière ligne montre n = 8) ; puis le cube RGB : 8 sommets, complémentaires, centre
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]
sommets = [(r, g, b) for r in (0, 255) for g in (0, 255) for b in (0, 255)]   # le cube RGB
print(len(sommets), all(tuple(255 - c for c in v) in sommets for v in sommets), tuple(sum(v[i] for v in sommets) / 8 for i in range(3)))# 8 True (127.5, 127.5, 127.5)
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. La table complète jusqu'à 14 : \(\zeta(2)=\frac{\pi^{2}}6\), \(\zeta(4)=\frac{\pi^{4}}{90}\), \(\zeta(6)=\frac{\pi^{6}}{945}\), \(\zeta(8)=\frac{\pi^{8}}{9450}\), \(\zeta(10)=\frac{\pi^{10}}{93\,555}\), \(\zeta(12)=\frac{691\,\pi^{12}}{638\,512\,875}\) et \(\zeta(14)=\frac{2\,\pi^{14}}{18\,243\,225}\). Le 691 vient de \(B_{12}=-\frac{691}{2730}\) ; c'est le même 691 que dans la congruence de Ramanujan pour \(\tau(n)\) (L·61).

sorte loifamille comptage ; valeurs de ζ
# k = 1 à 15, écart relatif ; puis B₂, B₄, B₆ en fractions ; enfin la table exacte de ζ(2) à ζ(14)
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)]
from sympy import zeta as Z, pi as PI
print([str(Z(2*k) / PI**(2*k)) for k in range(1, 8)])# ['1/6', '1/90', '1/945', '1/9450', '1/93555', '691/638512875', '2/18243225']
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. Après 2, 3 et 5, par exemple, \((1-2^{-s})(1-3^{-s})(1-5^{-s})\,\zeta(s)=1+\frac1{7^{s}}+\frac1{11^{s}}+\frac1{13^{s}}+\cdots\) : il ne reste que les entiers premiers avec 30. En développant le produit fini, \(k\) parenthèses à deux termes donnent \(2^{k}\) produits. Le crible est donc une inclusion-exclusion, et c'est le développement complet de \(\prod(1-p^{-s})\) qui donne \(1/\zeta(s)=\sum\mu(n)/n^{s}\). 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). Rangé par nombre de facteurs, le développement de \(\prod_p(1-p^{-s})\) s'écrit \(1-\sum\frac1{p^{s}}+\sum\frac1{(pq)^{s}}-\sum\frac1{(pqr)^{s}}+\cdots\) : chaque premier choisi apporte un \(-1\), donc un produit de \(k\) premiers distincts reçoit le signe \((-1)^{k}\), qui est exactement \(\mu(n)\). Les classes successives, avec leurs signes : les premiers (−), puis A006881 (+ : 6, 10, 14, 15, 21…), A007304 (− : 30, 42, 66…), A046386 (+ : 210, 330, 390…), A046387 (−), A067885 (+), A123321 (−). Piège de référence : A179690 n'en fait pas partie. Elle liste les nombres \(p^{2}q^{2}rs\), qui ne sont pas sans carré et n'apparaissent donc pas dans le développement.

sorte loifamille nombres premiers ; valeurs de ζ
# un s complexe ; le crible après 2, 3, 5, 7 ; puis Mertens ; enfin, en s = 2, les classes par nombre de premiers, signées par μ, jusqu'à 10⁵
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
import math
from sympy import mobius
M = 10**5
omega, carre = [0]*(M + 1), bytearray(M + 1)
for q in premiers:
    if q > M: break
    for m in range(q, M + 1, q): omega[m] += 1
    for m in range(q*q, M + 1, q*q): carre[m] = 1
print(all((0 if carre[n] else (-1)**omega[n]) == mobius(n) for n in range(1, 10**4 + 1)))# True
print([[n for n in range(2, 400) if not carre[n] and omega[n] == k][:5] for k in (2, 3, 4)])# [[6, 10, 14, 15, 21], [30, 42, 66, 70, 78], [210, 330, 390]]
classes = [math.fsum(1/n**2 for n in range(1, M + 1) if not carre[n] and omega[n] == k) for k in range(7)]
print([round(c, 6) for c in classes])# [1.0, 0.452247, 0.063765, 0.003694, 0.000104, 1e-06, 0.0]
print(round(math.fsum((-1)**k * c for k, c in enumerate(classes)), 6), round(6/math.pi**2, 6))# 0.607927 0.607927
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. Appliquée aux tournées qui visitent chaque point d'une grille, la formule fixe leur aire à \(\tfrac N2-1\) (L·115).

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. Enfin, \(N/\ln N\) n'est qu'une estimation grossière : jusqu'à \(10^{7}\), \(\frac16\,N/\ln N\) donne 103 403 premiers par classe, 7 % trop bas, alors que \(\frac16\operatorname{li}(N)\) donne 110 820, à 0,05 % de la moyenne réelle 110 763. C'est le même logarithme intégral que pour \(\pi(x)\) (L·32).

sorte loifamille nombres premiers
# les six classes modulo 9 jusqu'à 10⁷ ; leur part, par N/ln N puis par li(N) ; 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
from mpmath import li
print(round(li(N) / 6))       # 110820
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). Par inversion de Möbius, version multiplicative de VIII·2 : \(\Phi_n(x)=\prod_{d\mid n}(x^{d}-1)^{\mu(n/d)}\). Par exemple, \(\Phi_6=\frac{(x^{6}-1)(x-1)}{(x^{3}-1)(x^{2}-1)}=x^{2}-x+1\). Pour \(p\) premier, \(\Phi_p=\frac{x^{p}-1}{x-1}=1+x+\dots+x^{p-1}\), une série géométrique finie (L·87). Elle est irréductible sur \(\mathbb Q\), comme le montre le critère d'Eisenstein appliqué à \(\Phi_p(x+1)\), et tous les \(\Phi_n\) le sont (théorème, démontré au XIXᵉ siècle). En \(x=1\), \(1+x+\dots+x^{n-1}=\prod_{d\mid n,\,d>1}\Phi_d(x)\) donne \(n=\prod_{d\mid n,\,d>1}\Phi_d(1)\). D'où \(\Phi_n(1)=p\) si \(n\) est une puissance d'un premier \(p\), et 1 sinon : \(\Phi_n(1)=e^{\Lambda(n)}\), la version multiplicative de \(\ln n=\sum_{d\mid n}\Lambda(d)\) (L·30).

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 Φ₁₀₅ ; enfin la formule de Möbius, Φ_p géométrique, et Φₙ(1) = e^Λ(n)
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
xm1 = lambda d: [1] + [0]*(d - 1) + [-1]                # xᵈ − 1
def moebius_prod(n):
    num, den = [1], [1]
    for d in range(1, n + 1):
        if n % d == 0 and mu(n // d) == 1: num = produit(num, xm1(d))
        if n % d == 0 and mu(n // d) == -1: den = produit(den, xm1(d))
    return divise(num, den)
print(all(moebius_prod(n) == Phi[n] for n in range(1, 211)), moebius_prod(6))# True [1, -1, 1]
print(all(Phi[p] == [1]*p for p in range(2, 211) if phi(p) == p - 1))# True
def eLambda(n):                                  # e^Λ(n) : p si n est une puissance de p, 1 sinon
    q = 2
    while n % q: q += 1
    while n % q == 0: n //= q
    return q if n == 1 else 1
print([sum(Phi[n]) for n in range(2, 17)], all(sum(Phi[n]) == eLambda(n) for n in range(2, 211)))# [2, 3, 2, 5, 1, 7, 2, 3, 1, 11, 1, 13, 1, 1, 2] True
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
L·73probabilités en 1/ζ(k)
\(\Pr\bigl(n\ \text{n'est divisible par aucune puissance } k\text{-ième}\bigr)\)
=
\(\dfrac{1}{\zeta(k)}\)

pour \(k\geq2\), au sens de la proportion parmi \(1,\dots,N\) quand \(N\to\infty\). C'est aussi la probabilité que \(k\) entiers tirés au hasard n'aient aucun facteur commun : chaque premier \(p\) échoue avec probabilité \(p^{-k}\), d'où \(\prod_p(1-p^{-k})=1/\zeta(k)\) par le produit d'Euler (L·47). Pour \(k=2\), \(6/\pi^{2}\approx60{,}8\,\%\) des entiers sont sans facteur carré (639 sur 1 050, soit 0,6086), et c'est la probabilité qu'un arbre d'un verger planté aux points entiers soit visible depuis l'origine, puisqu'il faut des coordonnées premières entre elles. En dimension 3, ou pour trois entiers, \(1/\zeta(3)\approx83{,}2\,\%\), l'inverse de la constante d'Apéry. Pour \(k=6\), 982 954 entiers sur un million, contre \(1/\zeta(6)=945/\pi^{6}=0{,}98295\ldots\) Les sans-carré se partagent à égalité entre \(\mu=+1\) (nombre pair de facteurs premiers distincts, 1 compris) et \(\mu=-1\) (nombre impair, premiers compris) : \(3/\pi^{2}\) chacun, et \(\mu=0\) pour le reste, \(1-6/\pi^{2}\approx39\,\%\). Ce partage équitable revient à dire que la somme de Mertens est négligeable devant \(N\) (L·52), un énoncé équivalent au théorème des nombres premiers. Attention : 6 = 2 × 3 n'a pas de facteur carré, donc \(\mu(6)=+1\) ; les zéros commencent par 4, 8, 9, 12, 16, 18…

sorte loifamille Möbius μ ; probabilités
# sans-carré jusqu'à 1 050 ; le partage μ = +1 / −1 ; les sans-puissance-6 à un million ; puis le verger et les triplets
from math import gcd, pi
from mpmath import zeta
N = 10**6
mu = [1]*(N+1); compose = bytearray(N+1)
for q in range(2, N+1):
    if not compose[q]:
        compose[2*q::q] = b'\x01' * len(compose[2*q::q])
        for m in range(q, N+1, q): mu[m] = -mu[m]
        for m in range(q*q, N+1, q*q): mu[m] = 0
print(sum(1 for n in range(1, 1051) if mu[n]), [n for n in range(1, 20) if mu[n] == 0], mu[6])# 639 [4, 8, 9, 12, 16, 18] 1
print(round(sum(1 for n in range(1, N+1) if mu[n] == 1)/N, 5), round(sum(1 for n in range(1, N+1) if mu[n] == -1)/N, 5), round(3/pi**2, 5))# 0.30407 0.30386 0.30396
libre6 = bytearray([1])*(N+1)
for q in range(2, 11): libre6[q**6::q**6] = bytearray(len(libre6[q**6::q**6]))
print(sum(libre6[1:]), float(1/zeta(6)))# 982954 0.9829525922645803
M = 1000                                       # le verger : points visibles de (0, 0)
print(round(sum(1 for a in range(1, M+1) for b in range(1, M+1) if gcd(a, b) == 1)/M**2, 5), round(6/pi**2, 5))# 0.60838 0.60793
M = 120                                        # trois entiers sans facteur commun
print(round(sum(1 for a in range(1, M+1) for b in range(1, M+1) for c in range(1, M+1) if gcd(gcd(a, b), c) == 1)/M**3, 4), round(float(1/zeta(3)), 4))# 0.8321 0.8319
L·74la formule de Legendre (crible)
\(\#\{n\leq x : \operatorname{pgcd}(n,P)=1\}\)
=
\(\sum_{d\mid P}\mu(d)\Bigl\lfloor\frac{x}{d}\Bigr\rfloor\)

pour \(P\) produit de premiers distincts : c'est le principe d'inclusion-exclusion, où \(\mu(d)\) décide si on ajoute ou retire les multiples de \(d\). Avec \(x=P\), on retrouve l'indicatrice d'Euler, et plus généralement \(\varphi(n)=\sum_{d\mid n}\mu(d)\,n/d\) ; par inversion de Möbius, c'est la même chose que \(\sum_{d\mid n}\varphi(d)=n\) (L·29). Legendre (1808) en a tiré un calcul exact de \(\pi(x)\) : en prenant pour \(P\) le produit des premiers jusqu'à \(\sqrt x\), il ne survit que 1 et les premiers entre \(\sqrt x\) et \(x\), d'où \(\pi(x)=\pi(\sqrt x)-1+\sum_{d\mid P}\mu(d)\lfloor x/d\rfloor\). Piège : \(\mu\) et \(\varphi\) sont multiplicatives, pas complètement multiplicatives. \(\mu(mn)=\mu(m)\mu(n)\) et \(\varphi(mn)=\varphi(m)\varphi(n)\) ne valent que si \(m\) et \(n\) sont premiers entre eux : \(\mu(4)=0\) mais \(\mu(2)^{2}=1\), \(\varphi(4)=2\) mais \(\varphi(2)^{2}=1\). En général, \(\varphi(mn)\,\varphi(g)=\varphi(m)\varphi(n)\,g\) avec \(g=\operatorname{pgcd}(m,n)\).

sorte loifamille Möbius μ ; indicatrice φ
# le crible contre le comptage direct ; φ(2310) et φ par Möbius ; π(10⁶) par Legendre ; puis le piège de la multiplicativité
from math import gcd, isqrt
from functools import lru_cache
from itertools import combinations
from random import randint, seed
N = 10**6
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, isqrt(N)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
P = [n for n in range(N+1) if crible[n]]
def mu(n):
    r, q = 1, 2
    while q*q <= n:
        if n % q == 0:
            n //= q
            if n % q == 0: return 0
            r = -r
        q += 1
    return -r if n > 1 else r
phi = lambda n: sum(1 for k in range(1, n+1) if gcd(k, n) == 1)
seed(1); Q = [2, 3, 5, 7, 11]; prodQ = 2310
def legendre(x):
    return sum((-1)**len(c) * (x // eval('*'.join(map(str, c)) or '1')) for r in range(6) for c in combinations(Q, r))
print(all(legendre(x) == sum(1 for n in range(1, x+1) if gcd(n, prodQ) == 1) for x in [randint(1, 10**4) for _ in range(200)]))# True
print(legendre(prodQ), phi(prodQ), all(phi(n) == sum(mu(d)*(n//d) for d in range(1, n+1) if n % d == 0) for n in range(1, 400)))# 480 480 True
@lru_cache(None)
def reste(x, a):                               # entiers ≤ x sans facteur parmi les a premiers premiers
    if a == 0 or x == 0: return x
    return reste(x, a-1) - reste(x // P[a-1], a-1)
a = sum(1 for q in P if q*q <= N)
print(reste(N, a) + a - 1, len(P))             # π(10⁶) par la méthode de Legendre# 78498 78498
paires = [(m, n) for m in range(1, 61) for n in range(1, 61)]
print(all(gcd(m, n) > 1 for m, n in paires if mu(m*n) != mu(m)*mu(n)), (mu(4), mu(2)**2), (phi(4), phi(2)**2))# True (0, 1) (2, 1)
print(all(phi(m*n)*phi(gcd(m, n)) == phi(m)*phi(n)*gcd(m, n) for m, n in paires))# True
L·75le théorème de von Kochcité · von Koch 1901
\(\pi(x)\)
=
\(\operatorname{Li}(x)+O\bigl(\sqrt x\,\ln x\bigr)\)

si et seulement si l'hypothèse de Riemann est vraie, où \(\operatorname{Li}(x)=\int_2^{x}\frac{dt}{\ln t}=\operatorname{li}(x)-\operatorname{li}(2)\), avec \(\operatorname{li}(2)\approx1{,}045\) (L·32). Von Koch (1901) a montré que cette précision équivaut exactement à l'hypothèse de Riemann (C·2) ; Schoenfeld (1976) en a donné une version chiffrée : si l'hypothèse est vraie, \(|\pi(x)-\operatorname{li}(x)|<\frac{\sqrt x\,\ln x}{8\pi}\) pour tout \(x\geq2657\). Le code la vérifie de 3 000 à 107, ce qui ne prouve rien mais montre l'ordre de grandeur. Deux pièges. \(\operatorname{Li}(x)\) n'est pas \(x\ln x+C\) : la dérivée de \(x\ln x\) vaut \(\ln x+1\) ; en fait \(\operatorname{Li}(x)\sim x/\ln x\). Et la somme \(\tfrac1{\ln2}+\tfrac1{\ln3}+\dots+\tfrac1{\ln N}\) approche bien \(\operatorname{Li}(N)\), mais à une constante près : pour \(N=10^{6}\), on trouve 78 627,34 (78 627,27 en s'arrêtant à \(N-1\)), entre \(\operatorname{Li}(N)=78\,626{,}50\) et \(\operatorname{li}(N)=78\,627{,}55\). Ces écarts d'une unité sont dérisoires devant l'erreur \(\sqrt x\ln x\), qui se compte en milliers.

sorte loifamille nombres premiers ; valeurs de ζ
# la borne de Schoenfeld de 3 000 à 10⁷ ; π, l'écart à li et la borne aux puissances de 10 ; puis Σ 1/ln n, Li et li
import math
from mpmath import li, pi
N = 10**7
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, math.isqrt(N)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
compte, c = [0]*(N+1), 0
for n in range(N+1):
    c += crible[n]; compte[n] = c
ok = all(abs(compte[x] - li(x)) < math.sqrt(x)*math.log(x)/(8*pi) for x in range(3000, N+1, 10**4))
print(ok)                                      # borne de Schoenfeld vérifiée de 3 000 à 10⁷# True
print([(10**k, compte[10**k], round(float(li(10**k) - compte[10**k]), 1), round(math.sqrt(10**k)*math.log(10**k)/(8*math.pi), 1)) for k in (4, 5, 6, 7)])# [(10000, 1229, 17.1, 36.6), (100000, 9592, 37.8, 144.9), (1000000, 78498, 129.5, 549.7), (10000000, 664579, 339.4, 2028.0)]
M = 10**6
print(round(math.fsum(1/math.log(n) for n in range(2, M+1)), 2), round(float(li(M) - li(2)), 2), round(float(li(M)), 2))# 78627.34 78626.5 78627.55
print(round(M*math.log(M)), round(M/math.log(M)))     # x ln x est hors sujet# 13815511 72382
L·76la série de Gram pour la fonction R de Riemann
\(R(x)=\sum_{n\geq1}\frac{\mu(n)}{n}\operatorname{li}\bigl(x^{1/n}\bigr)\)
=
\(1+\sum_{k\geq1}\frac{(\ln x)^{k}}{k\cdot k!\;\zeta(k+1)}\)

pour \(x>0\) (Gram, 1893), avec le logarithme intégral \(\operatorname{li}\) pris depuis 0 (L·32), pas \(\operatorname{Li}\) depuis 2. La série de Möbius converge très lentement, alors que celle de Gram converge comme celle de l'exponentielle, grâce au \(k!\) : c'est elle qu'on utilise pour calculer \(R\). On l'obtient en développant chaque \(\operatorname{li}(x^{1/n})\) en série de puissances de \(\ln x\), puis en sommant d'abord sur \(n\), ce qui fait apparaître \(\sum_n\mu(n)/n^{k+1}=1/\zeta(k+1)\) (VIII·2). \(R(x)\) est l'approximation de \(\pi(x)\) au cœur de la formule explicite de Riemann (L·70) : 78 527,4 pour 78 498 premiers jusqu'à un million.

sorte loifamille nombres premiers ; valeurs de ζ
# Gram contre la fonction R de mpmath ; l'écart de la série de Möbius avec 10, 100, 1 000 termes ; puis R(10ᵏ) contre π(10ᵏ)
from mpmath import mp, mpf, li, log, zeta, factorial, nsum, inf, riemannr, nstr
mp.dps = 20
def mu(n):
    r, q = 1, 2
    while q*q <= n:
        if n % q == 0:
            n //= q
            if n % q == 0: return 0
            r = -r
        q += 1
    return -r if n > 1 else r
gram = lambda x: 1 + nsum(lambda k: log(x)**k / (k*factorial(k)*zeta(k+1)), [1, inf])
x = mpf(10)**6
print(nstr(gram(x), 15), nstr(riemannr(x), 15))# 78527.3994291277 78527.3994291277
mobius = lambda x, K: sum(mu(n)/mpf(n) * li(x**(mpf(1)/n)) for n in range(1, K+1) if mu(n))
print([nstr(mobius(x, K) - gram(x), 3) for K in (10, 100, 1000)])   # la série de Möbius traîne# ['0.239', '-0.038', '-0.0159']
pis = {3: 168, 4: 1229, 5: 9592, 6: 78498, 7: 664579, 8: 5761455, 9: 50847534}
print([(k, pis[k], nstr(gram(mpf(10)**k), 9)) for k in (3, 6, 9)])# [(3, 168, '168.359446'), (6, 78498, '78527.3994'), (9, 50847534, '50847455.4')]
L·77la série de Lambert en base 10
\(\sum_{n\geq1}\frac{1}{10^{n}-1}\)
=
\(\sum_{k\geq1}\frac{d(k)}{10^{k}}=0{,}12232424342624452626442\ldots\)

où \(d(k)\) est le nombre de diviseurs de \(k\). Chaque terme est une fraction périodique, \(\frac1{10^{n}-1}=0{,}\underbrace{0\ldots0}_{n-1}1\,\underbrace{0\ldots0}_{n-1}1\ldots\), qui pose un 1 à toutes les positions multiples de \(n\) ; la position \(k\) reçoit donc un 1 par diviseur de \(k\). C'est la série de Lambert \(\sum x^{n}/(1-x^{n})=\sum d(k)\,x^{k}\) prise en \(x=1/10\) (OEIS A073668). Les décimales se lisent 1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6… : ce sont les \(d(k)\), jusqu'à ce qu'un \(d(k)\) atteigne 10 et provoque une retenue, la première fois en \(k=48\). En commençant à \(n=2\), on retire la ligne de 1 venue de \(1/9=0{,}111\ldots\), et les décimales deviennent \(d(k)-1\), le nombre de diviseurs autres que 1. Multipliée par 9, c'est la somme des inverses des répunits 1, 11, 111… (A065444, 1,1009181908…). Cette constante est irrationnelle : Erdős l'a montré en 1948 pour la base 2, Peter Borwein en 1991 pour toute base entière.

sorte loifamille fonctions arithmétiques ; séries
# la somme contre Σ d(k)/10ᵏ ; les décimales contre d(k) ; la retenue en k = 48 ; sans la ligne de 1 ; puis les répunits
from mpmath import mp, mpf, nsum, inf, nstr
from fractions import Fraction
mp.dps = 80
S = nsum(lambda n: 1/(mpf(10)**n - 1), [1, inf])
d = lambda k: sum(1 for j in range(1, k+1) if k % j == 0)
T = sum(Fraction(d(k), 10**k) for k in range(1, 300))           # Σ d(k)/10ᵏ, en exact
print(nstr(S, 40), abs(S - mpf(T.numerator)/T.denominator) < mpf(10)**-70)# 0.1223242434262445262644283446282644492448 True
chiffres = nstr(S, 70)[2:]
print([d(k) for k in range(1, 13)], chiffres[:12])# [1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6] 122324243426
print([(k, d(k), chiffres[k-1]) for k in (36, 46, 47, 48, 49)])     # la retenue de d(48) = 10# [(36, 9, '9'), (46, 4, '4'), (47, 2, '3'), (48, 10, '0'), (49, 3, '3')]
print(nstr(S - mpf(1)/9, 12), [d(k) - 1 for k in range(1, 9)])# 0.0112131323151 [0, 1, 1, 2, 1, 3, 1, 3]
print(nstr(9*S, 15), nstr(nsum(lambda n: 1/((mpf(10)**n - 1)/9), [1, inf]), 15))   # répunits# 1.1009181908362 1.1009181908362
L·78l'intégrale de Riemann pour ζ
\(\zeta(s)\,\Gamma(s)\)
=
\(\int_0^{\infty}\frac{u^{s-1}}{e^{u}-1}\,du\)

pour \(\operatorname{Re}s>1\). Preuve en deux lignes : \(\frac1{e^{u}-1}=\sum_{n\geq1}e^{-nu}\), et \(\int_0^{\infty}u^{s-1}e^{-nu}\,du=\Gamma(s)/n^{s}\) ; on somme sur \(n\). Riemann (1859) part de cette intégrale et la transforme en intégrale sur un contour du plan complexe, ce qui prolonge \(\zeta\) à tout le plan sauf \(s=1\). Rappel : \(\Gamma(x)=(x-1)!\) pour les entiers (L·17). Cas particuliers : \(s=2\) donne \(\pi^{2}/6\), \(s=4\) l'intégrale de Planck \(\pi^{4}/15\) (II·7). La sœur avec un \(+\) au dénominateur, celle de la statistique de Fermi–Dirac, donne la fonction êta alternée : \(\int_0^{\infty}\frac{u^{s-1}}{e^{u}+1}\,du=\eta(s)\,\Gamma(s)\).

sorte loifamille valeurs de ζ ; fonction Γ
# l'écart entre les deux membres pour des s réels et complexes ; s = 2 ; puis la version Fermi–Dirac
from mpmath import mp, mpc, quad, exp, inf, gamma, zeta, altzeta, nstr
mp.dps = 20
ecart = lambda s: abs(quad(lambda u: u**(s-1) / (exp(u) - 1), [0, 1, inf]) - zeta(s)*gamma(s))
print([nstr(ecart(s), 3) for s in (2, 3, 4, 2.5, 7, mpc(3, 2))])# ['0.0', '0.0', '0.0', '1.69e-21', '0.0', '8.47e-22']
print(nstr(quad(lambda u: u / (exp(u) - 1), [0, inf]), 15), nstr(zeta(2), 15))# 1.64493406684823 1.64493406684823
fd = lambda s: abs(quad(lambda u: u**(s-1) / (exp(u) + 1), [0, 1, inf]) - altzeta(s)*gamma(s))
print([nstr(fd(s), 3) for s in (2, 3, 4, 2.5)])    # Fermi–Dirac et la fonction êta# ['0.0', '0.0', '0.0', '0.0']
L·79la dérivée de ζ aux zéros triviaux
\(\zeta'(-2n)\)
=
\((-1)^{n}\,\frac{(2n)!}{2\,(2\pi)^{2n}}\,\zeta(2n+1)\)

pour tout entier \(n\geq1\). Aux entiers pairs négatifs, \(\zeta(-2n)=0\) : ce sont les zéros triviaux. La valeur se cache donc dans la dérivée. On l'obtient en dérivant l'équation fonctionnelle \(\zeta(s)=2^{s}\pi^{s-1}\sin\frac{\pi s}{2}\,\Gamma(1-s)\,\zeta(1-s)\) (L·20) : en \(s=-2n\), le sinus s'annule, mais sa dérivée vaut \(\frac\pi2(-1)^{n}\). On voit réapparaître les \(\zeta\) des entiers impairs, comme \(\zeta(3)\), qui n'ont pas de forme close connue (L·59). Exemple : \(\zeta'(-2)=-\zeta(3)/(4\pi^{2})\approx-0{,}0304\). Et en 0, la même équation donne \(\zeta'(0)=-\tfrac12\ln(2\pi)\).

sorte loifamille valeurs de ζ
# ζ(−2n) = 0 ; l'écart pour n = 1 à 5 ; ζ′(−2) ; puis ζ′(0)
from mpmath import mp, zeta, factorial, pi, log, nstr
mp.dps = 25
droite = lambda n: (-1)**n * factorial(2*n) / (2 * (2*pi)**(2*n)) * zeta(2*n + 1)
print([nstr(zeta(-2*n), 3) for n in range(1, 4)])          # les zéros triviaux# ['0.0', '0.0', '0.0']
print([nstr(zeta(-2*n, derivative=1) - droite(n), 3) for n in range(1, 6)])# ['-4.04e-28', '2.02e-28', '-2.02e-28', '8.08e-28', '-1.21e-27']
print(nstr(zeta(-2, derivative=1), 15), nstr(-zeta(3) / (4*pi**2), 15))# -0.0304484570583933 -0.0304484570583933
print(nstr(zeta(0, derivative=1), 15), nstr(-log(2*pi)/2, 15))# -0.918938533204673 -0.918938533204673
L·80le logarithme de ζ comme intégrale de π(x)
\(\ln\zeta(s)\)
=
\(s\int_2^{\infty}\frac{\pi(x)}{x\,(x^{s}-1)}\,dx\)

pour \(\operatorname{Re}s>1\). On part du produit d'Euler (L·47) et de la règle \(\ln(ab)=\ln a+\ln b\) : \(\ln\zeta(s)=-\sum_p\ln(1-p^{-s})\). Chaque terme est lui-même une intégrale, \(-\ln(1-p^{-s})=s\int_p^{\infty}\frac{dx}{x(x^{s}-1)}\), et en les additionnant, chaque \(x\) est compté autant de fois qu'il y a de premiers \(p\leq x\), d'où \(\pi(x)\). C'est le même pont entre escalier et série de Dirichlet que pour \(\psi\) (L·71), et c'est par là que Riemann a fait entrer les premiers dans \(\zeta\). Piège : \(\sum_p\ln(1-p^{-s})\) vaut \(\ln(1/\zeta(s))=-\ln\zeta(s)\), et non \(1/\ln\zeta(s)\). Pour \(s=2\), on a \(-0{,}4977\) d'un côté et \(2{,}0092\) de l'autre.

sorte loifamille nombres premiers ; valeurs de ζ
# un seul premier : −ln(1−2⁻²) en intégrale ; puis l'intégrale complète de π(x), tronquée à 10³, 10⁵, 10⁶ ; et le piège
from mpmath import mp, mpf, quad, inf, log, zeta, nstr
from sympy import primerange
mp.dps = 20
s = 2
print(nstr(-log(1 - mpf(2)**-s), 15), nstr(s * quad(lambda x: 1/(x*(x**s - 1)), [2, inf]), 15))# 0.287682072451781 0.287682072451781
P = list(primerange(2, 10**6))
G = lambda x: log(1 - mpf(x)**-s) / s          # primitive de 1/(x(xˢ−1))
def integrale(N):                              # π(x) est constant entre deux premiers
    Q = [q for q in P if q <= N]
    return s * (sum((k+1) * (G(Q[k+1]) - G(Q[k])) for k in range(len(Q)-1)) - len(Q) * G(Q[-1]))
print([nstr(integrale(N), 12) for N in (10**3, 10**5, 10**6)], nstr(log(zeta(s)), 12))# ['0.497573312656', '0.497699500222', '0.497700234695'] 0.497700302471
print(nstr(log(1/zeta(2)), 6), nstr(1/log(zeta(2)), 6))   # le piège# -0.4977 2.00924
L·81l'inversion de Möbius
\(g(n)=\sum_{d\mid n}f(d)\)
\(\Longleftrightarrow\)
\(f(n)=\sum_{d\mid n}\mu(d)\,g\!\left(\frac nd\right)\)

pour toutes fonctions \(f,g\) définies sur les entiers \(\geq1\). Tout repose sur une identité : \(\sum_{d\mid n}\mu(d)\) vaut 1 si \(n=1\) et 0 sinon. Pour \(n=p\) premier, c'est \(\mu(1)+\mu(p)=1-1=0\) ; avec \(k\) facteurs premiers distincts, c'est \((1-1)^{k}=0\). Exemples : \(\sum_{d\mid n}\varphi(d)=n\) (L·29) donne \(\varphi(n)=\sum_{d\mid n}\mu(d)\,\frac nd\) (L·74) ; \(\sum_{d\mid n}\Lambda(d)=\ln n\) (L·30) donne \(\Lambda(n)=-\sum_{d\mid n}\mu(d)\ln d\). En séries de Dirichlet, inverser revient à multiplier par \(1/\zeta(s)=\sum\mu(n)/n^{s}\). Riemann en a fait une version pour les fonctions de \(x\) : si \(J(x)=\sum_{k\geq1}\frac1k\pi\bigl(x^{1/k}\bigr)\), qui compte les puissances de premiers \(p^{k}\) avec le poids \(1/k\), alors \(\pi(x)=\sum_{n\geq1}\frac{\mu(n)}{n}J\bigl(x^{1/n}\bigr)\). C'est cette inversion qui transforme la formule explicite de \(J\) en celle de \(\pi\) (L·70).

sorte loifamille Möbius μ ; fonctions arithmétiques
# Σ μ(d) = [n = 1] jusqu'à 10⁴ ; une fonction au hasard inversée ; Λ par Möbius ; puis π retrouvé à partir de J, en fractions exactes
from fractions import Fraction as Fr
from math import log
from random import randint, seed
N = 10**4
mu = [1]*(N+1); compose = bytearray(N+1)
for q in range(2, N+1):
    if not compose[q]:
        compose[2*q::q] = b'\x01' * len(compose[2*q::q])
        for m in range(q, N+1, q): mu[m] = -mu[m]
        for m in range(q*q, N+1, q*q): mu[m] = 0
div = [[] for _ in range(N+1)]
for d in range(1, N+1):
    for m in range(d, N+1, d): div[m].append(d)
print(all(sum(mu[d] for d in div[n]) == (1 if n == 1 else 0) for n in range(1, N+1)))# True
seed(1); f = [0] + [randint(-50, 50) for _ in range(N)]
g = [0] + [sum(f[d] for d in div[n]) for n in range(1, N+1)]
print(all(f[n] == sum(mu[d] * g[n//d] for d in div[n]) for n in range(1, N+1)))# True
def Lam(n):                                    # von Mangoldt : ln p si n = pᵏ, sinon 0 (L·30)
    if n == 1: return 0.0
    q = div[n][1]                              # plus petit facteur premier
    while n % q == 0: n //= q
    return log(q) if n == 1 else 0.0
print(all(abs(Lam(n) + sum(mu[d] * log(d) for d in div[n])) < 1e-9 for n in range(1, 3000)))# True
pi_ = [0]*(N+1)
for n in range(2, N+1): pi_[n] = pi_[n-1] + (not compose[n])
def iroot(x, k):                               # ⌊x^(1/k)⌋, en entiers
    r = int(round(x ** (1/k)))
    while r**k > x: r -= 1
    while (r+1)**k <= x: r += 1
    return r
J = lambda x: sum(Fr(pi_[iroot(x, k)], k) for k in range(1, x.bit_length() + 1))
inv = lambda x: sum(Fr(mu[n], n) * J(iroot(x, n)) for n in range(1, x.bit_length() + 1))
print([(x, pi_[x], str(inv(x))) for x in (100, 1000, 10**4)])# [(100, 25, '25'), (1000, 168, '168'), (10000, 1229, '1229')]
L·82les mots de pile ou face
\(\mathbb E\bigl[\text{lancers avant le mot } w\bigr]\)
=
\(\sum_{k\,:\ \text{début}_k(w)\,=\,\text{fin}_k(w)}2^{k}\)

pour une pièce équilibrée, où la somme porte sur les longueurs \(k\) pour lesquelles les \(k\) premières lettres de \(w\) coïncident avec ses \(k\) dernières (\(k\) égal à la longueur de \(w\) compris). Dans une longue suite de lancers, chaque mot de longueur \(k\) apparaît avec la fréquence \(2^{-k}\) : 1/2, 1/4, 1/8… Mais le temps d'attente avant sa première apparition dépend de ses chevauchements avec lui-même. PF n'a que le chevauchement total : 4 lancers. PP se chevauche aussi sur une lettre : \(2+4=6\). En longueur 3 : PPF demande 8 lancers, PFP 10, PPP 14. Pourtant, en moyenne, deux apparitions successives de chaque mot restent espacées de \(2^{k}\) : un mot qui se chevauche arrive par grappes, donc il se fait attendre plus longtemps au départ. C'est la formule de Conway, et elle explique le jeu de Penney (1969) : quel que soit le mot de 3 lettres choisi par le premier joueur, le second peut en choisir un qui sort avant lui plus d'une fois sur deux. Contre PPP, FPP gagne 7 fois sur 8, car PPP ne gagne que s'il sort dès les trois premiers lancers.

sorte loifamille probabilités ; comptage
# Conway contre le calcul exact pour les 30 mots de 1 à 4 lettres ; les fréquences ; les attentes simulées ; puis le duel PPP contre FPP
from fractions import Fraction as Fr
from itertools import product
from random import choice, seed
conway = lambda w: sum(2**k for k in range(1, len(w)+1) if w[:k] == w[-k:])
def exact(w):                                  # chaîne de Markov : état = plus long début de w déjà lu
    n = len(w)
    def suivant(i, c):
        t = w[:i] + c
        return next(j for j in range(len(t), -1, -1) if t.endswith(w[:j]))
    M = [[Fr(0)]*(n+1) for _ in range(n)]      # E_i = 1 + ½ E_suivant(P) + ½ E_suivant(F), E_n = 0
    for i in range(n):
        M[i][i] += 1; M[i][n] = Fr(1)
        for c in 'PF':
            j = suivant(i, c)
            if j < n: M[i][j] -= Fr(1, 2)
    for i in range(n):                         # élimination de Gauss, en fractions
        piv = next(r for r in range(i, n) if M[r][i] != 0); M[i], M[piv] = M[piv], M[i]
        for r in range(n):
            if r != i and M[r][i] != 0:
                f = M[r][i] / M[i][i]; M[r] = [a - f*b for a, b in zip(M[r], M[i])]
    return M[0][n] / M[0][0]
mots = [''.join(t) for k in range(1, 5) for t in product('PF', repeat=k)]
print(all(exact(w) == conway(w) for w in mots))# True
print({w: conway(w) for w in ('PF', 'PP', 'PPF', 'PFP', 'PPP')})# {'PF': 4, 'PP': 6, 'PPF': 8, 'PFP': 10, 'PPP': 14}
seed(1); suite = ''.join(choice('PF') for _ in range(10**6))
print([round(sum(suite.startswith(w, i) for i in range(len(suite)))/len(suite), 4) for w in ('P', 'PP', 'PFP')])# [0.5006, 0.2507, 0.1253]
def attente(w):
    t = ''
    while not t.endswith(w): t += choice('PF')
    return len(t)
print([round(sum(attente(w) for _ in range(40000))/40000, 2) for w in ('PF', 'PP', 'PPP')])# [4.0, 5.98, 14.04]
def course(a, b):
    t = ''
    while True:
        t += choice('PF')
        if t.endswith(a): return a
        if t.endswith(b): return b
print(sum(course('PPP', 'FPP') == 'FPP' for _ in range(40000)) / 40000)# 0.87515
L·83la preuve par 9 et par 11
\(n=\sum_k a_k\,10^{k}\)
\(\equiv\)
\(\sum_k a_k\ \ (\mathrm{mod}\ 9)\)

où les \(a_k\) sont les chiffres de \(n\), \(a_0\) celui des unités. La raison tient en une ligne : \(10\equiv1\pmod 9\), donc chaque chiffre compte pour lui-même. Exemple : 12 345 et \(1+2+3+4+5=15\) laissent tous deux le reste 6 modulo 9. De même \(10\equiv-1\pmod{11}\), d'où la somme alternée en partant des unités : \(n\equiv a_0-a_1+a_2-a_3+\dots\pmod{11}\) ; pour 12 345, \(5-4+3-2+1=3\), et c'est bien le reste de 12 345 divisé par 11. Ce sont des congruences, pas seulement des tests de divisibilité. Pour vérifier une multiplication \(a\times b=c\), on compare les restes : si \(r(a)\,r(b)\not\equiv r(c)\), le calcul est faux. Mais la preuve par 9 est aveugle à toute erreur multiple de 9, en particulier à deux chiffres échangés : 56 088 et 56 808 ont le même reste modulo 9. La preuve par 11 voit l'échange de deux chiffres voisins (sauf s'ils sont égaux), et les deux ensemble ne laissent passer que les erreurs multiples de 99. Sur des fautes de frappe tirées au hasard, moitié chiffres changés, moitié chiffres voisins échangés, la preuve par 9 n'en repère qu'une sur deux, la preuve par 11 les repère toutes. Bonus : \(1001=7\times11\times13\), donc la somme alternée des tranches de trois chiffres (789 − 456 + 123 pour 123 456 789) teste 7, 11 et 13 d'un coup.

sorte loifamille fonctions arithmétiques ; opérations
# 20 000 nombres au hasard ; l'exemple 12 345 ; le produit aux chiffres échangés ; la part des fautes vues par 9, 11 et 99 ; puis le test par 1 001
from random import randint, seed, choice
seed(1)
chiffres = lambda n: [int(c) for c in str(n)[::-1]]          # unités d'abord
somme = lambda n: sum(chiffres(n))
alternee = lambda n: sum((-1)**k * a for k, a in enumerate(chiffres(n)))
tests = [randint(1, 10**12) for _ in range(20000)]
print(all(n % 9 == somme(n) % 9 and n % 11 == alternee(n) % 11 for n in tests))# True
print(12345 % 9, somme(12345) % 9, 12345 % 11, alternee(12345))# 6 6 3 3
c, faux = 123 * 456, 56808                     # le bon produit est 56 088 ; on échange deux chiffres
print(c, faux % 9 == c % 9, faux % 11 == c % 11)# 56088 True False
def erreur(n):                                 # une faute de frappe : un chiffre changé, ou deux voisins échangés
    t = list(str(n)); i = randint(0, len(t) - 2)
    if choice([0, 1]): t[i], t[i+1] = t[i+1], t[i]
    else: t[i] = str((int(t[i]) + randint(1, 9)) % 10)
    return int(''.join(t))
E = [(n, erreur(n)) for n in tests]
E = [(n, m) for n, m in E if m != n]
vu = lambda q: sum(n % q != m % q for n, m in E) / len(E)
print(round(vu(9), 3), round(vu(11), 3), round(vu(99), 3))  # part des fautes détectées# 0.513 1.0 1.0
tranches = lambda n: sum((-1)**k * int(str(n)[::-1][3*k:3*k+3][::-1]) for k in range((len(str(n)) + 2)//3))
print(all(n % q == tranches(n) % q for n in tests for q in (7, 11, 13)), tranches(123456789))# True 456
L·84les relations du triangle
\(\frac{a}{\sin A}=\frac{b}{\sin B}=\frac{c}{\sin C}\)
=
\(2R=\frac{abc}{2K}\)

pour un triangle de côtés \(a,b,c\) opposés aux angles \(A,B,C\), avec \(A+B+C=\pi\), \(s=\frac{a+b+c}2\) le demi-périmètre, \(r\) et \(R\) les rayons des cercles inscrit et circonscrit, et \(K\) l'aire. C'est la loi des sinus ; elle implique \(a\leq b\leq c\iff A\leq B\leq C\). Autour d'elle : Al-Kashi, \(a^{2}=b^{2}+c^{2}-2bc\cos A\), qui redonne Pythagore pour \(A=90^\circ\) ; les projections, \(a=b\cos C+c\cos B\) ; Héron, \(K=\sqrt{s(s-a)(s-b)(s-c)}=rs\), avec aussi \(K=\tfrac12ab\sin C=\frac{abc}{4R}=\frac{a^{2}\sin B\sin C}{2\sin A}\) ; la loi des tangentes, \(\frac{a+b}{a-b}=\frac{\tan\frac{A+B}2}{\tan\frac{A-B}2}\) ; et les formules de Mollweide (appelées aussi formules de Newton), \(\frac{a+b}{c}=\frac{\cos\frac{A-B}2}{\sin\frac C2}\) et \(\frac{a-b}{c}=\frac{\sin\frac{A-B}2}{\cos\frac C2}\). En prime, l'inégalité d'Euler : \(R\geq2r\), avec égalité seulement pour le triangle équilatéral.

sorte loifamille géométrie
# 10 000 triangles mesurés à partir de trois points ; l'écart maximal sur 14 relations ; puis l'inégalité d'Euler et le cas équilatéral
import math, random
random.seed(1)
def triangle():                                # trois points au hasard : tout est mesuré, rien n'est supposé
    P = [(random.uniform(-5, 5), random.uniform(-5, 5)) for _ in range(3)]
    d = lambda U, V: math.dist(U, V)
    def angle(O, U, V):
        u, v = (U[0]-O[0], U[1]-O[1]), (V[0]-O[0], V[1]-O[1])
        return abs(math.atan2(u[0]*v[1] - u[1]*v[0], u[0]*v[0] + u[1]*v[1]))
    a, b, c = d(P[1], P[2]), d(P[2], P[0]), d(P[0], P[1])
    A, B, C = angle(P[0], P[1], P[2]), angle(P[1], P[2], P[0]), angle(P[2], P[0], P[1])
    K = abs((P[1][0]-P[0][0])*(P[2][1]-P[0][1]) - (P[2][0]-P[0][0])*(P[1][1]-P[0][1])) / 2   # lacet
    (x1, y1), (x2, y2), (x3, y3) = P               # centre du cercle circonscrit
    D = 2*(x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2))
    ux = ((x1*x1+y1*y1)*(y2-y3) + (x2*x2+y2*y2)*(y3-y1) + (x3*x3+y3*y3)*(y1-y2)) / D
    uy = ((x1*x1+y1*y1)*(x3-x2) + (x2*x2+y2*y2)*(x1-x3) + (x3*x3+y3*y3)*(x2-x1)) / D
    R = math.dist((ux, uy), P[0])
    I = ((a*x1 + b*x2 + c*x3)/(a+b+c), (a*y1 + b*y2 + c*y3)/(a+b+c))      # centre du cercle inscrit
    r = abs((x3-x2)*(y2-I[1]) - (x2-I[0])*(y3-y2)) / a                      # distance de I à (BC)
    return a, b, c, A, B, C, K, R, r
pire, ordre, euler = 0, True, []
for _ in range(10000):
    a, b, c, A, B, C, K, R, r = triangle()
    if K < 0.5: continue                       # on écarte les triangles presque plats
    s = (a + b + c) / 2
    ecarts = [A + B + C - math.pi, a/math.sin(A) - 2*R, b/math.sin(B) - 2*R, c/math.sin(C) - 2*R,
              a*a - (b*b + c*c - 2*b*c*math.cos(A)), a - (b*math.cos(C) + c*math.cos(B)),
              K - math.sqrt(s*(s-a)*(s-b)*(s-c)), K - r*s, K - a*b*c/(4*R), K - a*b*math.sin(C)/2,
              K - a*a*math.sin(B)*math.sin(C)/(2*math.sin(A)),
              (a+b)/c - math.cos((A-B)/2)/math.sin(C/2), (a-b)/c - math.sin((A-B)/2)/math.cos(C/2),
              (a+b)*math.tan((A-B)/2) - (a-b)*math.tan((A+B)/2)]
    pire = max(pire, max(abs(e) for e in ecarts))
    ordre &= (a <= b) == (A <= B)
    euler.append(R / r)
print(pire, ordre)                             # 14 relations, sur des triangles mesurés# 5.4853899200679734e-12 True
print(round(min(euler), 4), round(max(euler), 1))   # Euler : R/r ≥ 2# 2.0 1982.2
h = math.sqrt(3)/2                             # le triangle équilatéral de côté 1
print(round(1/math.sqrt(3), 12), round(h/3, 12), round((1/math.sqrt(3)) / (h/3), 12))# 0.57735026919 0.288675134595 2.0
L·85le produit d'Euler fini
\(\prod_{p\leq P}\frac{p}{p-1}\)
=
\(\sum_{\substack{n\geq1\\ \text{facteurs premiers}\ \leq P}}\frac1n\)

pour tout \(P\), avec égalité exacte entre un produit fini et une série convergente. Chaque facteur est une série géométrique (L·87), \(\frac{p}{p-1}=1+\frac1p+\frac1{p^{2}}+\dots\) ; en développant le produit, chaque entier dont les facteurs premiers sont \(\leq P\) apparaît exactement une fois, grâce à l'unicité de la décomposition en facteurs premiers. Les premières valeurs : 2, 3, 15/4, 35/8, 77/16, 1001/192… ; leurs numérateurs forment la suite A060753 de l'OEIS et leurs dénominateurs A038110. Par exemple, \(2\cdot\frac32\cdot\frac54=\frac{15}4=1+\frac12+\frac13+\frac14+\frac15+\frac16+\frac18+\frac19+\dots\), en ne gardant que les nombres construits avec 2, 3 et 5. Quand \(P\to\infty\), tous les entiers finissent par apparaître : la série harmonique diverge, donc le produit aussi, et il y a une infinité de premiers (Euler, 1737 ; L·47). Mertens (1874) en précise la croissance : \(\prod_{p\leq P}\frac{p}{p-1}\approx e^{\gamma}\ln P\). Cette valeur est aussi la borne supérieure, jamais atteinte, de l'abondance \(\sigma(k)/k\) quand \(k\) n'a que des facteurs premiers \(\leq P\) (Laatsch, 1986).

sorte loifamille nombres premiers ; valeurs de ζ
# les fractions pour P = 2 à 13 ; les sommes sur les nombres friables jusqu'à 10¹² ; l'abondance qui plafonne sous 15/4 ; puis Mertens à un million
from fractions import Fraction as Fr
from math import exp, log
from mpmath import euler
premiers = [2, 3, 5, 7, 11, 13]
prod, valeurs = Fr(1), []
for q in premiers:
    prod *= Fr(q, q - 1); valeurs.append(str(prod))
print(valeurs)                # ['2', '3', '15/4', '35/8', '77/16', '1001/192']
def friables(P, B):                            # les n ≤ B dont tous les facteurs premiers sont ≤ P
    nums = [1]
    for q in [q for q in premiers if q <= P]:
        nums = [m * q**k for m in nums for k in range(64) if m * q**k <= B]
    return nums
print([round(sum(1/n for n in friables(P, 10**12)), 9) for P in (2, 3, 5, 7)], [2, 3, 3.75, 4.375])# [2.0, 3.0, 3.75, 4.374999998] [2, 3, 3.75, 4.375]
def abondance(n, P):                           # σ(n)/n, calculé sur la factorisation
    r = Fr(1)
    for q in [q for q in premiers if q <= P]:
        a = 0
        while n % q == 0: n //= q; a += 1
        r *= Fr(q**(a+1) - 1, q**a * (q - 1))
    return r
meilleur = max(abondance(n, 5) for n in friables(5, 10**9))
print(float(meilleur), meilleur < Fr(15, 4))  # tend vers 15/4 sans l'atteindre# 3.746171055169753 True
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]))
m = 1.0
for q in range(2, N+1):
    if crible[q]: m *= q / (q - 1)
print(round(m, 4), round(exp(float(euler)) * log(N), 4))   # Mertens# 24.6074 24.6064
L·86la somme des inverses des nombres premiers
\(\sum_{p\leq x}\frac1p\)
=
\(\ln\ln x+M+o(1)\)

quand \(x\to\infty\), avec la constante de Meissel–Mertens \(M=\gamma+\sum_p\bigl(\ln(1-\tfrac1p)+\tfrac1p\bigr)=0{,}2614972128\ldots\) Euler (1737) a montré que cette somme diverge, en prenant le logarithme du produit d'Euler (L·85) ; Mertens (1874) en a donné la vitesse exacte. Elle est d'une lenteur folle : elle dépasse 1 dès \(p=5\) et 2 à \(p=277\), mais il faut attendre \(p=5\,195\,977\) pour dépasser 3, et la formule annonce le seuil de 4 vers \(1{,}8\times10^{18}\). Elle diverge pourtant, alors que \(\sum1/n^{2}\) converge (II·1) : les premiers sont donc « plus nombreux » que les carrés, au sens où la somme de leurs inverses est infinie. Conséquence de la formule : sur un intervalle \([2^{u},2^{v}]\), la somme des \(1/p\) vaut environ \(\ln\ln2^{v}-\ln\ln2^{u}=\ln\frac vu\), exactement comme la somme des \(1/n\) pour \(u

sorte loifamille nombres premiers
# les seuils 1, 2, 3 ; la somme contre ln ln x + M ; M recalculé ; puis le seuil de 4 ; enfin l'exemple dyadique : 1/n sur ]100, 200], 1/p sur ]2¹¹, 2²²], et la borne de Rosser–Schoenfeld
import math
from mpmath import euler
N = 10**7
crible = bytearray([1])*(N+1); crible[0] = crible[1] = 0
for q in range(2, math.isqrt(N)+1):
    if crible[q]: crible[q*q::q] = bytearray(len(crible[q*q::q]))
S, seuils, valeurs, reste = 0.0, {}, {}, 0.0
for n in range(2, N+1):
    if crible[n]:
        S += 1/n
        reste += math.log(1 - 1/n) + 1/n
        for t in (1, 2, 3):
            if S > t and t not in seuils: seuils[t] = n
    if n in (10**4, 10**5, 10**6, 10**7): valeurs[n] = S
print(seuils)                 # {1: 5, 2: 277, 3: 5195977}
M = 0.26149721284764278375
print([(x, round(valeurs[x], 5), round(math.log(math.log(x)) + M, 5)) for x in (10**4, 10**5, 10**6, 10**7)])# [(10000, 2.48306, 2.48182), (100000, 2.70527, 2.70497), (1000000, 2.88733, 2.88729), (10000000, 3.04145, 3.04144)]
print(round(float(euler) + reste, 9), M)      # M recalculé à partir de γ# 0.261497216 0.26149721284764277
print(f"{math.exp(math.exp(4 - M)):.2e}")     # le seuil de 4 annoncé par la formule# 1.80e+18
from mpmath import harmonic
print(round(float(harmonic(200) - harmonic(100)), 5), round(float(harmonic(200) - harmonic(99)), 5), round(math.log(2), 5))# 0.69065 0.70065 0.69315
print(round(sum(1/n for n in range(2**11 + 1, 2**22 + 1) if crible[n]), 5), round(math.log(22/11), 5))# 0.69064 0.69315
borne = lambda x: 1 / (2 * math.log(x)**2)
print(f"{borne(2.0**100) + borne(2.0**200):.1e}")# 1.3e-04
L·87la série géométrique
\(\sum_{k=0}^{n}x^{k}\)
=
\(\frac{x^{n+1}-1}{x-1}\)

pour tout \(x\neq1\) (pour \(x=1\), la somme vaut \(n+1\)). Preuve : en multipliant la somme par \(x-1\), tous les termes intermédiaires s'annulent deux à deux. Si \(|x|<1\), \(x^{n+1}\) tend vers 0, d'où \(\sum_{k\geq0}x^{k}=\frac1{1-x}\). Retournée, pour \(|x|>1\) : \(\sum_{n\geq0}x^{-n}=\frac{x}{x-1}=\frac1{1-1/x}\), soit 2, 3/2, 4/3, 5/4 pour \(x=2,3,4,5\), et \(\frac1{x-1}\), soit 1, 1/2, 1/3, 1/4, en partant de \(n=1\). C'est elle qui donne \(0{,}999\ldots=\frac9{10}\cdot\frac1{1-1/10}=1\), et les facteurs du produit d'Euler \(\frac1{1-p^{-s}}\) (L·47, L·85). Pièges : pour \(|x|\geq1\), la série infinie diverge. En \(x=-1\), la série de Grandi \(1-1+1-1+\dots\) a des sommes partielles 1, 0, 1, 0… sans limite ; elle ne « vaut » ½ qu'au sens d'une moyenne (Cesàro), ou comme limite de \(\frac1{1+x}\) quand \(x\to1^{-}\) (Abel).

sorte loifamille opérations
# la formule exacte en fractions ; les séries en 1/2ⁿ … 1/5ⁿ ; 0,999… ; puis Grandi, avec ses moyennes
from fractions import Fraction as Fr
from random import randint, seed
seed(1)
ok = True
for _ in range(2000):
    x, n = Fr(randint(-50, 50), randint(1, 20)), randint(0, 30)
    if x != 1: ok &= sum(x**k for k in range(n+1)) == (x**(n+1) - 1) / (x - 1)
print(ok, sum(Fr(1)**k for k in range(8)))     # et 8 pour x = 1, n = 7# True 8
print([float(sum(Fr(1, x)**n for n in range(200))) for x in (2, 3, 4, 5)])# [2.0, 1.5, 1.3333333333333333, 1.25]
print([float(sum(Fr(1, x)**n for n in range(1, 200))) for x in (2, 3, 4, 5)])# [1.0, 0.5, 0.3333333333333333, 0.25]
print(Fr(9, 10) / (1 - Fr(1, 10)))            # 0,999… = 1# 1
partielles = [sum((-1)**k for k in range(n+1)) for n in range(10)]
print(partielles, sum(partielles) / len(partielles), round(1 / (1 + 0.999999), 6))   # Grandi# [1, 0, 1, 0, 1, 0, 1, 0, 1, 0] 0.5 0.5
L·88les nombres harmoniques généralisés
\(H_k^{(r)}=\sum_{n=1}^{k}\frac{1}{n^{r}}\)
=
\(\zeta(r)-\frac{1}{(r-1)\,k^{r-1}}+\frac{1}{2k^{r}}-\frac{r}{12\,k^{r+1}}+\dots\)

pour \(r>1\), quand \(k\) grandit (Euler–Maclaurin, L·58). On note aussi \(H_{k,r}\) ; pour \(r=1\), ce sont les nombres harmoniques \(H_k=1+\frac12+\dots+\frac1k\), avec \(H_{k+1}=H_k+\frac1{k+1}\). Les sommes partielles convergent vers \(\zeta(r)\) seulement si \(r>1\) ; pour \(r=1\), elles divergent comme \(\ln k+\gamma\) (XI·2), où \(\gamma\) joue le rôle de la constante. Le reste décroît lentement : avec 1 000 termes, \(H^{(2)}_{1000}=1{,}64393\ldots\) n'a que trois décimales justes de \(\pi^{2}/6=1{,}64493\ldots\), car il manque environ \(1/k\). Mais en ajoutant les trois termes correctifs, on gagne une douzaine de chiffres d'un coup : c'est ainsi qu'Euler a pu calculer \(\zeta(2)\) avec de nombreuses décimales, avant même de savoir que c'était \(\pi^{2}/6\). En Mathematica : Sum[1/n^2, {n, 1, Infinity}] donne \(\pi^{2}/6\), et HarmonicNumber[k, r] donne \(H_k^{(r)}\).

sorte loifamille nombres harmoniques ; valeurs de ζ
# H₁₀₀₀⁽²⁾ contre π²/6 ; le gain des trois termes correctifs pour r = 2, 3/2, 3, 4 ; le cas r = 1 ; puis la récurrence
from mpmath import mp, mpf, zeta, pi, log, euler, nstr
mp.dps = 30
H = lambda k, r: sum(mpf(1) / n**r for n in range(1, k + 1))
k = 1000
corrige = lambda k, r: H(k, r) + mpf(1)/((r - 1) * k**(r - 1)) - mpf(1)/(2 * k**r) + mpf(r)/(12 * k**(r + 1))
print(nstr(H(k, 2), 12), nstr(pi**2 / 6, 12))# 1.64393456668 1.64493406685
print(nstr(corrige(k, 2), 15), nstr(abs(corrige(k, 2) - zeta(2)), 3))# 1.64493406684823 3.33e-17
print([nstr(abs(corrige(k, r) - zeta(r)), 3) for r in (mpf(3)/2, 3, 4)])# ['5.76e-16', '8.33e-20', '1.67e-22']
print(nstr(H(k, 1), 12), nstr(log(k) + euler + mpf(1)/(2*k), 12))      # r = 1 : ln k + γ# 7.48547086055 7.48547094388
print(all(H(j + 1, 1) == H(j, 1) + mpf(1)/(j + 1) for j in range(1, 50)))# True
L·89Gelfond–Schneider et les presque-égalitéscité · Gelfond–Schneider 1934
\(a^{b}\)
\(\text{est}\)
\(\text{transcendant}\)

dès que \(a\) et \(b\) sont algébriques, avec \(a\neq0,1\) et \(b\) irrationnel ; c'était le septième problème de Hilbert (1900), résolu en 1934 par Gelfond et Schneider. Ainsi \(e^{\pi}=(-1)^{-i}\) est transcendant (on part de \(-1=e^{i\pi}\)), tout comme \(2^{\sqrt2}\) et \(i^{\,i}=e^{-\pi/2}\). Conséquence : aucune formule algébrique ne peut valoir \(e^{\pi}\). Or \(\frac{e^{\pi}}{60}+\frac9{28}=0{,}70710678\mathbf{197}\ldots\) quand \(\frac1{\sqrt2}=0{,}70710678\mathbf{119}\ldots\), un accord sur 9 chiffres. Si c'était une égalité, \(e^{\pi}=60\bigl(\frac1{\sqrt2}-\frac9{28}\bigr)\) serait algébrique : c'est donc une coïncidence, et le théorème le prouve. Est-elle extraordinaire ? Dans la seule famille \(\frac{e^{\pi}}a+\frac bc\) avec \(a,c\leq100\) (4 168 candidats), la chance de tomber aussi près par hasard est d'environ 1 sur 3 000. C'est rare, mais si l'on a fouillé des milliers de familles pour la dénicher, c'est attendu : plus on cherche, plus on trouve. Une simple fraction fait d'ailleurs mieux : \(e^{\pi}\approx\frac{10691}{462}\) à \(8\times10^{-9}\) près, contre \(5\times10^{-8}\) pour \(e^{\pi}\approx30\sqrt2-\frac{135}7\), grâce au grand quotient 591 de la fraction continue \(e^{\pi}=[23;7,9,3,1,1,591,\dots]\). Pour séparer une vraie identité d'une coïncidence, on utilise l'algorithme PSLQ à haute précision : une identité tient sur des centaines de chiffres (c'est ainsi qu'a été découverte la formule BBP pour \(\pi\), en 1995), une coïncidence casse vite. Ici, PSLQ ne trouve aucune relation entière entre \(e^{\pi}\), \(\sqrt2\) et 1 à coefficients \(\leq10^{4}\) sur 40 chiffres. D'autres presque-égalités : \(e^{\pi}-\pi=19{,}99909\ldots\), qui ne vaut pas 20 puisque \(\pi\) et \(e^{\pi}\) sont algébriquement indépendants (Nesterenko, 1996) ; \(H_8=2{,}71786\ldots\approx e\) (XIV·1). Mais certaines ont une raison : \(e^{\pi\sqrt{163}}=262\,537\,412\,640\,768\,743{,}99999999999925\ldots\) est presque l'entier \(640320^{3}+744\), parce que 163 est un nombre de Heegner et que la fonction \(j\) prend en \(\frac{1+\sqrt{-163}}2\) une valeur entière. Ce nombre reste transcendant par Gelfond–Schneider, puisque \(e^{\pi\sqrt{163}}=(-1)^{-i\sqrt{163}}\).

sorte loifamille exponentielle complexe
# (−1)^(−i) = e^π et i^i ; ta presque-égalité ; les 4 168 candidats et la chance d'en faire autant ; la fraction continue et 10691/462 ; PSLQ ; puis e^π − π, H₈ et les nombres de Heegner
from mpmath import mp, mpf, mpc, exp, pi, sqrt, power, e, floor, pslq, nstr
from fractions import Fraction
import math
mp.dps = 50
print(nstr(power(-1, mpc(0, -1)) - exp(pi), 5), nstr(power(mpc(0, 1), mpc(0, 1)) - exp(-pi/2), 5))# (0.0 + 0.0j) (0.0 + 0.0j)
v = exp(pi)/60 + mpf(9)/28
print(nstr(v, 20), nstr(1/sqrt(2), 20), nstr(v - 1/sqrt(2), 5))# 0.70710678197489257867 0.7071067811865475244 7.8835e-10
E, t, essais, chance = math.exp(math.pi), 1/math.sqrt(2), [], 0.0
for a in range(1, 101):
    for c in range(1, 101):
        b = round((t - E/a) * c)               # le meilleur b pour ce couple (a, c)
        if 0 <= b <= c and math.gcd(b, c) == 1:
            essais.append((abs(E/a + b/c - t), a, b, c))
            chance += 2 * c * 7.9e-10          # l'écart est ~uniforme sur [0, 1/2c] : P(écart < 7,9e-10) = 2c × 7,9e-10
essais.sort()
print(len(essais), [(f"{d:.1e}", a, b, c) for d, a, b, c in essais[:3]], round(1/chance))# 4168 [('7.9e-10', 60, 9, 28), ('6.0e-06', 72, 27, 70), ('9.0e-06', 48, 9, 40)] 3073
x, fc = exp(pi), []
for _ in range(8):
    fc.append(int(floor(x))); x = 1/(x - fc[-1])
print(fc, nstr(exp(pi) - mpf(10691)/462, 3), nstr(exp(pi) - (30*sqrt(2) - mpf(135)/7), 3))# [23, 7, 9, 3, 1, 1, 591, 2] -7.91e-9 4.73e-8
mp.dps = 40
print(pslq([exp(pi), sqrt(2), 1], maxcoeff=10**4, maxsteps=10**6))   # None : aucune relation entière# None
mp.dps = 50
H8 = sum(Fraction(1, k) for k in range(1, 9))
print(nstr(exp(pi) - pi, 12), nstr(e - mpf(H8.numerator)/H8.denominator, 6))# 19.9990999792 0.000424686
print([(h, nstr(exp(pi*sqrt(h)) - (c**3 + 744), 6)) for h, c in ((43, 960), (67, 5280), (163, 640320))])# [(43, '-0.000222534'), (67, '-1.33755e-6'), (163, '-7.49927e-13')]
L·90les sommes de Ramanujan
\(c_q(n)=\sum_{\substack{1\leq a\leq q\\ \operatorname{pgcd}(a,q)=1}}e^{2\pi i\,an/q}\)
=
\(\sum_{d\mid\operatorname{pgcd}(n,q)}\mu\!\left(\frac qd\right)d\)

pour tous entiers \(q,n\geq1\) : c'est la somme des racines primitives \(q\)-ièmes de l'unité élevées à la puissance \(n\). La seconde forme (Kluyver, 1906) montre que ce sont toujours des entiers. Les premières sont des cosinus : \(c_2(n)=\cos(n\pi)=(-1)^{n}\), \(c_3(n)=2\cos\frac{2\pi n}3\), qui donne \(-1,-1,2\) en boucle, et \(c_4(n)=2\cos\frac{\pi n}2\), qui donne \(0,-2,0,2\). En \(n\), elles sont périodiques de période \(q\). Valeurs remarquables : \(c_q(1)=\mu(q)\) (L·52) et \(c_q(q)=\varphi(q)\). Ramanujan (1918) s'en est servi pour développer des fonctions arithmétiques comme des séries de Fourier, par exemple \(\frac{\sigma(n)}{n}=\frac{\pi^{2}}6\sum_{q\geq1}\frac{c_q(n)}{q^{2}}\), où \(\sigma(n)\) est la somme des diviseurs. Voir aussi la page Ramanujan's Sum de nimbers.

sorte loifamille exponentielle complexe ; fonctions arithmétiques
# les deux formes pour q, n ≤ 40 ; tes trois cosinus ; c_q(1) = μ(q) et c_q(q) = φ(q) ; la période ; puis le développement de σ(n)/n
import cmath
from math import gcd, pi
def mu(n):
    r, q = 1, 2
    while q*q <= n:
        if n % q == 0:
            n //= q
            if n % q == 0: return 0
            r = -r
        q += 1
    return -r if n > 1 else r
phi = lambda n: sum(1 for a in range(1, n+1) if gcd(a, n) == 1)
expo = lambda q, n: sum(cmath.exp(2j*cmath.pi*a*n/q) for a in range(1, q+1) if gcd(a, q) == 1)
kluyver = lambda q, n: sum(mu(q//d) * d for d in range(1, q+1) if q % d == 0 and n % d == 0)
print(all(abs(expo(q, n) - kluyver(q, n)) < 1e-9 for q in range(1, 41) for n in range(1, 41)))# True
print([kluyver(2, n) for n in range(1, 9)], [kluyver(3, n) for n in range(1, 9)], [kluyver(4, n) for n in range(1, 9)])# [-1, 1, -1, 1, -1, 1, -1, 1] [-1, -1, 2, -1, -1, 2, -1, -1] [0, -2, 0, 2, 0, -2, 0, 2]
print(all(kluyver(q, 1) == mu(q) and kluyver(q, q) == phi(q) for q in range(1, 300)))# True
print(all(kluyver(q, n + q) == kluyver(q, n) for q in range(1, 40) for n in range(1, 40)))# True
sigma = lambda n: sum(d for d in range(1, n+1) if n % d == 0)
print([(n, round(sigma(n)/n, 6), round(pi**2/6 * sum(kluyver(q, n)/q**2 for q in range(1, 20001)), 6)) for n in (1, 6, 12)])# [(1, 1.0, 1.0), (6, 2.0, 2.0), (12, 2.333333, 2.333333)]
L·91le dénominateur de H_n
\(\operatorname{den}(H_n)\ \mid\ \operatorname{ppcm}(1,\dots,n)\)
\(\mid\)
\(n!\)

où \(H_n=1+\frac12+\dots+\frac1n\) s'écrit en fraction irréductible \(\frac{\text{A001008}(n)}{\text{A002805}(n)}\) (numérateurs de Wolstenholme, L·38). Le ppcm (A003418) est un dénominateur commun naturel, et il divise \(n!\). Les quotients ont leurs suites : \(n!/\operatorname{ppcm}\) = A025527 ; \(\operatorname{ppcm}/\operatorname{den}(H_n)\) = A110566 ; leur produit \(n!/\operatorname{den}(H_n)\) = A056612, qui vaut aussi \(\operatorname{pgcd}(n!,\,n!\,H_n)\) ; et l'entier \(\operatorname{ppcm}\cdot H_n=\sum_{k\leq n}\operatorname{ppcm}/k\) = A025529 = A001008 × A110566. Le facteur A110566 vaut 1 presque toujours ; il est divisible par un premier \(p\) exactement quand \(p\) divise le numérateur de \(H_m\), où \(m=\lfloor n/p^{k}\rfloor\) et \(p^{k}\) est la plus grande puissance de \(p\) inférieure ou égale à \(n\) (pour \(n=6\) : \(p=3\), \(m=2\), et \(H_2=3/2\)), ce qui renvoie aux ensembles d'Eswarathasan et Levine (C·4). Il est toujours impair : la plus grande puissance de 2 inférieure à \(n\) ne se simplifie jamais, et c'est elle qui empêche \(H_n\) d'être entier (L·37).

sorte loifamille nombres harmoniques ; fonctions arithmétiques
# la chaîne de divisibilité ; A025527 et A110566 ; le produit A056612 ; A025529 entier ; puis où A110566 décolle, et sa parité
from fractions import Fraction
from math import lcm, factorial, gcd
N = 1000
H, P, lignes = Fraction(0), 1, []
for n in range(1, N+1):
    H += Fraction(1, n); P = lcm(P, n)
    lignes.append((n, H.numerator, H.denominator, P))
print(all(P % d == 0 and factorial(n) % P == 0 for n, a, d, P in lignes[:300]))# True
print([factorial(n) // P for n, a, d, P in lignes[:12]])           # A025527# [1, 1, 1, 2, 2, 12, 12, 48, 144, 1440, 1440, 17280]
print([P // d for n, a, d, P in lignes[:24]])                       # 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]
print(all(factorial(n) // d == (factorial(n) // P) * (P // d) == gcd(factorial(n), factorial(n) * a // d) for n, a, d, P in lignes[:200]))# True
print([a * (P // d) for n, a, d, P in lignes[:10]], all(P * a // d == sum(P // k for k in range(1, n+1)) for n, a, d, P in lignes[:200]))# [1, 3, 11, 25, 137, 147, 1089, 2283, 7129, 7381] True
print([n for n, a, d, P in lignes if P // d > 1][:12], all((P // d) % 2 == 1 for n, a, d, P in lignes))# [6, 7, 8, 18, 19, 20, 21, 22, 23, 24, 25, 26] True
L·92le critère de la racine
\(N\ \text{premier}\)
\(\iff\)
\(\text{aucun premier }p\text{ tel que }p^{2}\leq N\text{ ne divise }N\)

pour tout entier \(N\geq2\). Pour savoir si \(N\) est premier, on le divise par la suite des nombres premiers \(2,3,5,7,\dots\). On s'arrête dès qu'un d'eux divise \(N\) exactement, et alors \(N\) n'est pas premier. Sinon, on s'arrête quand le premier suivant dépasse \(\sqrt N\), et alors \(N\) est premier. Exemple : \(\sqrt{47}=6{,}85565\ldots\). Les divisions de 47 par 2, 3 et 5 laissent les restes 1, 2 et 2, donc 47 est premier, sans essayer 7, puisque \(7\times7=49>47\). La raison : si \(N=a\,b\) avec \(1

sorte loifamille nombres premiers ; fonctions arithmétiques
# ton exemple 47 ; le critère contre isprime jusqu'à 200 000 ; le plus petit facteur ≤ √N ; le piège des carrés de premiers ; puis 168 divisions au lieu de 78 498 pour 1 000 003
from math import isqrt
from sympy import isprime, primerange, factorint
racine = lambda N: N > 1 and all(N % p for p in primerange(2, isqrt(N) + 1))
mal_borne = lambda N: N > 1 and all(N % p for p in primerange(2, isqrt(N) + 1) if p*p < N)
print(isqrt(47), [47 % p for p in (2, 3, 5)], 7*7 > 47, racine(47))# 6 [1, 2, 2] True True
print(all(racine(N) == isprime(N) for N in range(1, 200001)))# True
print(all(min(factorint(N))**2 <= N for N in range(4, 200001) if not isprime(N)))# True
print([N for N in range(2, 200001) if mal_borne(N) != isprime(N)][:8])# [4, 9, 25, 49, 121, 169, 289, 361]
print(all(mal_borne(N) != isprime(N) for N in (p*p for p in primerange(2, 448))))# True
print(len(list(primerange(2, isqrt(1000003) + 1))), len(list(primerange(2, 1000003))), racine(1000003))# 168 78498 True
L·93λ de Dirichlet aux entiers pairs
\(\lambda(2k)=\sum_{n=0}^{\infty}\frac{1}{(2n+1)^{2k}}\)
=
\(\frac{(2^{2k}-1)\,|B_{2k}|}{2\,(2k)!}\;\pi^{2k}\)

pour tout entier \(k\geq1\), où \(B_{2k}\) est un nombre de Bernoulli. On garde seulement les impairs de \(\zeta\) : \(\lambda(s)=(1-2^{-s})\,\zeta(s)\) (II·5), et la formule d'Euler pour \(\zeta(2k)\) (L·25) donne le reste. Les cinq premières valeurs : \(\frac{\pi^{2}}8=1{,}23370\ldots\), \(\frac{\pi^{4}}{96}=1{,}01468\ldots\), \(\frac{\pi^{6}}{960}=1{,}00145\ldots\), \(\frac{17\,\pi^{8}}{161\,280}=1{,}00016\ldots\) et \(\frac{31\,\pi^{10}}{2\,903\,040}=1{,}00002\ldots\) Le carnet a ainsi trois cousines : \(\zeta\) aux entiers pairs avec les nombres de Bernoulli (L·25), \(\beta\) aux entiers impairs avec les nombres d'Euler (L·26), et \(\lambda\) aux entiers pairs, la somme des impairs sans signes alternés, de nouveau avec Bernoulli. Avec les signes alternés en \(s=2\), on tombe sur la constante de Catalan \(G\) (III·1), dont on ne connaît aucune forme close. Quand \(k\) grandit, \(\lambda(2k)\) tend vers 1, parce que le terme \(1/3^{2k}\) écrase tous les suivants : l'excès \(\lambda(s)-1\) se comporte comme \(3^{-s}\).

sorte loifamille valeurs de ζ ; Bernoulli
# tes cinq coefficients ; la formule exacte contre (1 − 2⁻²ᵏ)ζ(2k) pour k ≤ 15 ; l'écart numérique ; tes valeurs ; puis l'excès divisé par 3⁻ˢ, qui tend vers 1
from sympy import bernoulli, factorial, zeta as Z, pi as PI, Rational, simplify
from mpmath import mp, mpf, nsum, inf, pi, nstr
mp.dps = 25
coef = lambda k: (2**(2*k) - 1) * abs(bernoulli(2*k)) / (2 * factorial(2*k))
print([str(coef(k)) for k in range(1, 6)])# ['1/8', '1/96', '1/960', '17/161280', '31/2903040']
print(all(simplify(coef(k) * PI**(2*k) - (1 - Rational(1, 2**(2*k))) * Z(2*k)) == 0 for k in range(1, 16)))# True
lam = lambda s: nsum(lambda n: 1/(2*n + 1)**s, [0, inf])
print(nstr(max(abs(lam(2*k) - mpf(coef(k).p) / coef(k).q * pi**(2*k)) for k in range(1, 16)), 3))# 1.55e-25
print([nstr(lam(2*k), 9) for k in range(1, 6)])# ['1.23370055', '1.01467803', '1.00144708', '1.00015518', '1.00001704']
print([nstr((lam(s) - 1) * mpf(3)**s, 6) for s in (12, 20, 40)])# ['1.00222', '1.00004', '1.0']
L·94les caractères de Dirichlet
\(\frac{1}{\varphi(k)}\sum_{\chi\bmod k}\overline{\chi(a)}\,\chi(n)\)
=
\(\begin{cases}1 & \text{si } n\equiv a\ (\mathrm{mod}\ k)\\ 0 & \text{sinon}\end{cases}\)

pour \(a\) premier avec \(k\) : c'est l'orthogonalité des caractères. Un caractère de Dirichlet modulo \(k\) est une suite \(\chi(n)\) qui vérifie trois règles : \(\chi(1)=1\), \(\chi(n+k)=\chi(n)\) (période \(k\)), \(\chi(mn)=\chi(m)\,\chi(n)\) (multiplicative pour tous \(m,n\)), avec \(\chi(n)=0\) dès que \(n\) a un facteur commun avec \(k\). Il y en a exactement \(\varphi(k)\). Le caractère principal vaut 1 sur tous les \(n\) premiers avec \(k\). Modulo 5, il y en a quatre ; sur \(n=1,2,3,4\), ils valent \((1,1,1,1)\), \((1,i,-i,-1)\), \((1,-1,-1,1)\) et \((1,-i,i,-1)\). Le troisième est le symbole de Legendre, qui répond à la question « \(n\) est-il un carré modulo 5 ? ». Modulo 6, il y en a deux : sur \(n=1,5\), ils valent \((1,1)\) et \((1,-1)\). Modulo 4, \(\chi_4\) vaut \(+1\) sur \(1+4\mathbb Z\) et \(-1\) sur \(3+4\mathbb Z\) ; modulo 12, \(\chi_{12}\) vaut \(+1\) sur 1 et 11 et \(-1\) sur 5 et 7. À chaque caractère, Dirichlet (1837) associe une série \(L(s,\chi)=\sum_{n\geq1}\chi(n)\,n^{-s}\). Comme \(\chi\) est multiplicative, elle a un produit d'Euler, \(L(s,\chi)=\prod_p\frac{1}{1-\chi(p)\,p^{-s}}\) (L·47). Pour le caractère principal, c'est \(\zeta\) privée des facteurs d'Euler des premiers qui divisent \(k\) : modulo 3, \(L(s,\chi_0)=1+\frac1{2^{s}}+0+\frac1{4^{s}}+\frac1{5^{s}}+0+\cdots=(1-3^{-s})\,\zeta(s)\), comme II·5 retire le facteur de 2. Pour \(\chi_4\), c'est la fonction \(\beta\) : \(L(1,\chi_4)=\frac\pi4\) (I·2) et \(L(2,\chi_4)=G\) (III·1). Pour \(\chi_{12}\), on obtient une perle (I·5). L'orthogonalité est l'outil de la preuve du théorème de Dirichlet (L·66) : elle isole une seule progression \(n\equiv a\) parmi toutes les autres, en combinant les \(\varphi(k)\) séries \(L\). Il reste ensuite à montrer que \(L(1,\chi)\neq0\) pour tout caractère non principal, ce qui est le cœur difficile de la preuve.

sorte loifamille nombres premiers ; exponentielle complexe
# tes tables mod 5, 6 et 12 vérifient les trois règles ; l'orthogonalité ; les φ(p) caractères mod p jusqu'à 37 ; puis le produit d'Euler de χ₄ (premiers < 10⁵) contre G et β(3) = π³/32 (L·26) ; enfin le principal mod 3, (1 − 3⁻ˢ)ζ(s)
from math import gcd
from cmath import exp, pi
from mpmath import mp, mpf, fprod, catalan, nstr, pi as PI
from sympy import primerange, totient, primitive_root
def car(k, v):                                   # χ défini sur les classes premières avec k
    return lambda n: 0 if gcd(n, k) > 1 else v[n % k]
mod5 = [car(5, dict(zip((1, 2, 3, 4), t))) for t in ((1, 1, 1, 1), (1, 1j, -1j, -1), (1, -1, -1, 1), (1, -1j, 1j, -1))]
mod6 = [car(6, {1: 1, 5: 1}), car(6, {1: 1, 5: -1})]
mod12 = [car(12, {1: 1, 5: a, 7: b, 11: a*b}) for a in (1, -1) for b in (1, -1)]
regles = lambda c, k: c(1) == 1 and all(c(n + k) == c(n) and abs(c(m)*c(n) - c(m*n)) < 1e-12 for m in range(1, 3*k) for n in range(1, 3*k))
print(all(regles(c, 5) for c in mod5), all(regles(c, 6) for c in mod6), all(regles(c, 12) for c in mod12))# True True True
ortho = lambda cs, k: all(abs(sum(complex(c(a)).conjugate() * c(n) for c in cs) / len(cs) - (n % k == a)) < 1e-12 for a in range(1, k) if gcd(a, k) == 1 for n in range(1, 4*k))
print(ortho(mod5, 5), ortho(mod6, 6), ortho(mod12, 12))# True True True
def tous(p):                                     # les p − 1 caractères modulo p premier, via une racine primitive g
    g = primitive_root(p); ind = {pow(g, m, p): m for m in range(p - 1)}
    return [car(p, {r: exp(2j*pi*j*ind[r]/(p - 1)) for r in ind}) for j in range(p - 1)]
print(all(len(tous(p)) == totient(p) and ortho(tous(p), p) for p in primerange(3, 40)))# True
chi4 = lambda n: (0, 1, 0, -1)[n % 4]
euler = lambda s: fprod(1 / (1 - chi4(q) * mpf(q)**-s) for q in primerange(3, 10**5))
mp.dps = 20
print(nstr(euler(2), 8), nstr(catalan, 8), nstr(euler(3), 8), nstr(PI**3 / 32, 8))# 0.9159656 0.91596559 0.96894615 0.96894615
from mpmath import zeta
chi0 = lambda n: 0 if n % 3 == 0 else 1          # principal modulo 3
print(nstr(fprod(1 / (1 - chi0(q) * mpf(q)**-2) for q in primerange(2, 10**5)), 8), nstr((1 - mpf(3)**-2) * zeta(2), 8))# 1.4621624 1.4621636
L·95compter les premiers par le PPCM
\(\pi(n)\)
=
\(\omega\bigl(\operatorname{ppcm}(1,\dots,n)\bigr)=\omega\bigl(e^{\psi(n)}\bigr)\)

pour tout entier \(n\geq1\), où \(\omega(m)\) compte les facteurs premiers distincts de \(m\) et \(\psi\) est la seconde fonction de Chebyshev (VIII·3, L·30), à ne pas confondre avec la fonction digamma, notée aussi \(\psi\) (I·5). Comme \(e^{\psi(n)}=\operatorname{ppcm}(1,\dots,n)\) et que chaque premier \(p\leq n\) y figure, ses facteurs premiers distincts sont exactement les premiers jusqu'à \(n\). Exemple : \(\operatorname{ppcm}(1,\dots,10)=2520=2^{3}\cdot3^{2}\cdot5\cdot7\), donc \(\omega=4=\pi(10)\). Version jumelle avec la primorielle : \(\pi(n)=\omega(n\#)=\omega\bigl(e^{\theta(n)}\bigr)\). C'est une reformulation, pas un raccourci de calcul, puisqu'il faut connaître les premiers pour factoriser le PPCM. Elle explique pourtant L·53 : chaque premier double le nombre de diviseurs, donc \(d(\operatorname{ppcm})\geq2^{\pi(n)}\). Piège : \(\pi(x)\approx\frac{x}{\ln x}\) n'est qu'une approximation, pas une égalité. Pour le nombre de premiers jusqu'à \(\sqrt n\), elle donne \(\pi(\sqrt n)\approx\frac{\sqrt n}{\ln\sqrt n}=\frac{2\sqrt n}{\ln n}\), soit 144,8 pour \(n=10^{6}\), alors qu'il y a 168 premiers jusqu'à 1 000 : 14 % trop bas. Le logarithme intégral (L·32) fait bien mieux : \(\operatorname{li}(1000)=177{,}6\).

sorte loifamille nombres premiers ; PPCM
# ppcm(1, …, 10) = 2520 ; la formule pour n ≤ 3 000 ; la version primorielle ; puis π(√n) contre 2√n/ln n et li(√n)
from math import lcm, log, sqrt, isqrt
from functools import reduce
from sympy import primepi, primefactors, primorial
from mpmath import li
omega = lambda m: len(primefactors(m))
P = reduce(lcm, range(1, 11))
print(P, omega(P), primepi(10))# 2520 4 4
L, ok = 1, True
for n in range(1, 3001):
    L = lcm(L, n); ok = ok and omega(L) == primepi(n)
print(ok)                     # True
print(all(omega(primorial(n, nth=False)) == primepi(n) for n in range(2, 1001)))# True
print([(n, int(primepi(isqrt(n))), round(2*sqrt(n)/log(n), 1), round(float(li(isqrt(n))), 1)) for n in (10**4, 10**6, 10**8)])# [(10000, 25, 21.7, 30.1), (1000000, 168, 144.8, 177.6), (100000000, 1229, 1085.7, 1246.1)]
L·96la loi du levier
\(F_1\,d_1\)
=
\(F_2\,d_2\)

à l'équilibre, quand deux forces font tourner un levier en sens contraires (Archimède, IIIᵉ siècle av. J.-C.). Le produit d'une force par son bras de levier est son moment, ou couple, en N·m. Plus précisément, \(\tau=d\,F\sin\theta\) : seule compte la part de la force perpendiculaire au bras, et une force dirigée vers l'axe ne produit aucun couple. Exemple : 1 lb à 3 ft équilibre 3 lb à 1 ft. Un train d'engrenages multiplie les rapports : avec trois étages de rapports 2, 3 et 3, une masse de 1 kg en retient \(2\times3\times3=18\). Rien n'est gratuit pour autant : la corde de 1 kg doit descendre 18 fois plus loin que la charge ne monte. Le travail \(F\times\text{déplacement}\) est le même des deux côtés, et c'est le principe des travaux virtuels. Tout cela néglige les frottements.

sorte loifamille mécanique ; moments
# 1 000 tirages : τ = r × F contre d F sin θ ; le levier 1 × 3 = 3 × 1 et les forces dans l'axe ; ton train 2·3·3 ; puis 1 000 trains au hasard, où force × déplacement se conserve
import math, random
random.seed(1)
tir = lambda: (random.uniform(-5, 5), random.uniform(-5, 5))
couple = lambda r, F: r[0]*F[1] - r[1]*F[0]
sinus = lambda r, F: math.sin(math.atan2(F[1], F[0]) - math.atan2(r[1], r[0]))
err = max(abs(couple(r, F) - math.hypot(*r) * math.hypot(*F) * sinus(r, F)) for r, F in ((tir(), tir()) for _ in range(1000)))
print(f"{err:.1e}")           # 1.4e-14
print(1 * 3 == 3 * 1, couple((2, 0), (-7, 0)), couple((0, 1.5), (0, 4)))# True 0 0.0
statique = lambda etages, F: F * math.prod(R / r for R, r in etages)
cinematique = lambda etages, s: s * math.prod(r / R for R, r in etages)
print(statique([(2, 1), (3, 1), (3, 1)], 1), cinematique([(2, 1), (3, 1), (3, 1)], 18))# 18.0 1.0
trains = [[(random.uniform(1, 9), random.uniform(0.2, 3)) for _ in range(random.randint(1, 6))] for _ in range(1000)]
print(f"{max(abs(statique(t, 1) * cinematique(t, 1) - 1) for t in trains):.1e}")# 7.8e-16
L·97l'oscillateur harmonique
\(T\)
=
\(2\pi\sqrt{\frac mk}\)

pour une masse \(m\) (la bille) tenue par un ressort de raideur \(k\), qui la rappelle avec la force \(-k\,x\) (loi de Hooke). L'équation \(m\,x''=-k\,x\) a pour solutions \(x(t)=A\cos(\omega t+\varphi)\), avec la pulsation \(\omega=\sqrt{k/m}\) en rad/s. D'où la période \(T=2\pi/\omega\) et la fréquence \(f=\frac1T=\frac{1}{2\pi}\sqrt{\frac km}\) : le passage de \(\frac{1}{2\pi/\sqrt{k/m}}\) à \(\frac{\sqrt{k/m}}{2\pi}\) est un simple retournement de fraction. Trois conséquences : un ressort quatre fois plus raide double la fréquence ; une bille quatre fois plus lourde double la période ; et surtout la période ne dépend pas de l'amplitude \(A\). C'est l'isochronisme, et il est exact pour le ressort idéal. Pour le pendule, il ne vaut qu'aux petits angles. L'énergie \(\frac12mv^{2}+\frac12kx^{2}=\frac12kA^{2}\) passe sans cesse de la vitesse au ressort et revient, sans se perdre. Le même cosinus relie ce mouvement au cercle (XII·1) : c'est l'ombre d'un point qui tourne à vitesse constante.

sorte loifamille mécanique ; oscillations
# 50 couples (k, m) au hasard : période mesurée contre 2π√(m/k) ; trois amplitudes ; ressort ×4 et masse ×4 ; puis la dérive d'énergie
import math, random
random.seed(1)
def mesure(k, m, A, h=1e-3):                     # RK4 sur x'' = −(k/m)x, période entre deux montées par 0
    f = lambda x, v: (v, -k/m * x)
    x, v, t, passages = A, 0.0, 0.0, []
    E0 = 0.5*k*A*A; derive = 0.0
    while len(passages) < 2:
        a1 = f(x, v); a2 = f(x + h/2*a1[0], v + h/2*a1[1]); a3 = f(x + h/2*a2[0], v + h/2*a2[1]); a4 = f(x + h*a3[0], v + h*a3[1])
        xn = x + h/6*(a1[0] + 2*a2[0] + 2*a3[0] + a4[0]); vn = v + h/6*(a1[1] + 2*a2[1] + 2*a3[1] + a4[1])
        if x < 0 <= xn: passages.append(t + h * (-x) / (xn - x))
        x, v, t = xn, vn, t + h
        derive = max(derive, abs(0.5*m*v*v + 0.5*k*x*x - E0) / E0)
    return passages[1] - passages[0], derive
tirages = [(random.uniform(1, 20), random.uniform(0.2, 3)) for _ in range(50)]
print(f"{max(abs(mesure(k, m, 1)[0] / (2*math.pi*math.sqrt(m/k)) - 1) for k, m in tirages):.1e}")# 1.6e-09
print([round(mesure(4, 1, A)[0], 6) for A in (0.01, 1, 100)], round(math.pi, 6))# [3.141593, 3.141593, 3.141593] 3.141593
print(round(mesure(16, 1, 1)[0] / mesure(4, 1, 1)[0], 6), round(mesure(4, 4, 1)[0] / mesure(4, 1, 1)[0], 6))# 0.5 2.0
print(f"{max(mesure(k, m, 1)[1] for k, m in tirages[:10]):.1e}")# 7.5e-12
L·98le théorème des nombres premierscité · Hadamard, de la Vallée Poussin 1896
\(\pi(x)\)
\(\sim\)
\(\frac{x}{\ln x}\)

quand \(x\to\infty\), au sens où le rapport tend vers 1. Conjecturé par Gauss et Legendre vers 1800, il a été démontré en 1896 par Hadamard et de la Vallée Poussin, grâce aux zéros de \(\zeta\) (L·70). Il a trois lectures équivalentes. La première : \(\pi(x)\sim x/\ln x\). La deuxième : près de \(x\), un entier tiré au hasard est premier avec une probabilité d'environ \(1/\ln x\). Cette densité tend vers 0, mais si lentement que la somme des \(1/p\) diverge (L·86). La troisième : le \(n\)-ième premier vérifie \(p_n\sim n\ln n\). Trois pièges. D'abord, le logarithme est le logarithme naturel \(\ln\), pas \(\log_{10}=\ln/\ln10\). Entre \(10^{6}\) et \(10^{6}+10^{4}\), il y a 753 premiers ; \(10^{4}/\ln10^{6}\) en prévoit 724, mais \(10^{4}/\log_{10}10^{6}\) en prévoirait 1 667. Ensuite, parmi les seuls impairs, la probabilité double : \(2/\ln x\). Enfin, les trois formules ne sont justes qu'au premier ordre. \(n\ln n\) donne 13,8 millions pour \(p_{10^{6}}=15\,485\,863\) ; la correction de Cesàro, \(n(\ln n+\ln\ln n-1)\), donne 15,44 millions. Pour compter les premiers, \(\operatorname{li}(x)\) (L·32) et \(R(x)\) (L·76) font bien mieux que \(x/\ln x\).

sorte loifamille nombres premiers ; logarithme
# π(10ᵏ) : le rapport à x/ln x tend vers 1, lentement, et celui à li bien plus vite ; la densité, en ln puis en log₁₀ ; la part des impairs ; puis p_n et Cesàro
from math import log, log10
from sympy import primepi, primerange, prime
from mpmath import li
print([(k, int(primepi(10**k)), round(primepi(10**k) * log(10**k) / 10**k, 4), round(float(primepi(10**k) / li(10**k)), 6)) for k in (3, 5, 7, 9)])# [(3, 168, 1.1605, 0.945895), (5, 9592, 1.1043, 0.996074), (7, 664579, 1.0712, 0.99949), (9, 50847534, 1.0537, 0.999967)]
x, L = 10**6, 10**4
P = list(primerange(x, x + L))
print(len(P), round(L / log(x), 1), round(L / log10(x), 1))# 753 723.8 1666.7
print(round(len(P) / (L / 2), 4), round(2 / log(x), 4), round(1 / log(x), 4))# 0.1506 0.1448 0.0724
n = 10**6
print(prime(n), round(n * log(n)), round(n * (log(n) + log(log(n)) - 1)))# 15485863 13815511 15441302
L·99compter les diviseurs avec des cosinus
\(d(n)=\sum_{s=1}^{n}\Bigl\lfloor\cos^{2}\frac{\pi n}{s}\Bigr\rfloor\)
=
\(\sum_{s=1}^{n}\frac1s\sum_{j=0}^{s-1}\cos\frac{2\pi jn}{s}\)

pour tout entier \(n\geq1\), où \(d(n)\) compte les diviseurs de \(n\). L'idée : \(\cos^{2}(\pi n/s)\) vaut 1 exactement quand \(s\) divise \(n\), puisque l'angle est alors un multiple de \(\pi\), et reste strictement inférieur à 1 sinon. La partie entière garde donc 1 pour chaque diviseur et 0 pour les autres \(s\). Piège : sans la partie entière, la formule est fausse. Pour \(n=6\), \(1+\sum_{s=2}^{6}\cos^{2}(6\pi/s)\) vaut environ 4,655, alors que 6 a 4 diviseurs. La seconde forme est exacte sans partie entière : \(\frac1s\sum_{j}e^{2i\pi jn/s}\) vaut 1 si \(s\mid n\) et 0 sinon, parce que les racines \(s\)-ièmes de l'unité se compensent (L·34). Le même mécanisme, restreint aux racines primitives, donne les sommes de Ramanujan (L·90).

sorte loifamille fonctions arithmétiques ; racines de l'unité
# la forme à partie entière jusqu'à 2 000 ; la forme exacte par les racines de l'unité jusqu'à 400 ; le piège sans partie entière ; puis d(1) à d(12)
from math import cos, pi, floor
from sympy import divisor_count
plancher = lambda n: sum(floor(cos(pi*n/s)**2) for s in range(1, n+1))
racines = lambda n: round(sum(sum(cos(2*pi*j*n/s) for j in range(s)) / s for s in range(1, n+1)))
print(all(plancher(n) == divisor_count(n) for n in range(1, 2001)))# True
print(all(racines(n) == divisor_count(n) for n in range(1, 401)))# True
print([(n, round(1 + sum(cos(pi*n/s)**2 for s in range(2, n+1)), 3), int(divisor_count(n))) for n in (6, 10, 12)])# [(6, 4.655, 4), (10, 5.933, 4), (12, 8.309, 6)]
print([plancher(n) for n in range(1, 13)])# [1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6]
L·100la suite de Thue–Morse
\(\prod_{k\geq0}\bigl(1-x^{2^{k}}\bigr)\)
=
\(\sum_{n\geq0}t(n)\,x^{n}\)

pour \(|x|<1\), avec \(t(n)=(-1)^{s(n)}=1-2s(n)\), où \(s(n)\) est la parité du nombre de 1 dans l'écriture binaire de \(n\). La suite \(s\) : 0, 01, 0110, 01101001, 0110100110010110… Elle se construit de trois façons. Par miroir : on recopie le mot en échangeant 0 et 1. Par substitution : \(0\mapsto01\) et \(1\mapsto10\). Par récurrence : \(s(2n)=s(n)\) et \(s(2n+1)=1-s(n)\). Le produit se développe ainsi parce que chaque \(n\) s'écrit d'une seule façon comme somme de puissances de 2 distinctes, et chaque puissance choisie apporte un signe \(-1\) (L·47). Les \(n\) avec \(s(n)=0\) sont les nombres « maléfiques » (A001969 : 0, 3, 5, 6, 9…) ; les autres sont « odieux » (A000069 : 1, 2, 4, 7, 8…). Prouhet (1851) : entre 0 et \(2^{m}-1\), les deux camps ont les mêmes sommes de puissances \(k\)-ièmes pour \(k=0,\dots,m-1\). Par exemple \(0+3=1+2\), et \(0+3+5+6=1+2+4+7\) avec aussi \(0^{2}+3^{2}+5^{2}+6^{2}=1^{2}+2^{2}+4^{2}+7^{2}=70\). Piège : l'égalité s'arrête à \(k=m-1\). Pour les cubes, on trouve 368 contre 416 ; il faut passer à 16 nombres pour l'obtenir. Vue sur l'hypercube (L·14), \(s\) colorie les \(2^{m}\) sommets par la parité de leurs 1 : deux sommets voisins diffèrent d'un seul chiffre, donc changent toujours de couleur. La même suite donne un produit infini remarquable (IV·4).

sorte loifamille binaire ; comptage
# miroir, substitution et récurrence donnent le même mot ; le produit développé jusqu'à x⁶³ ; maléfiques et odieux ; Prouhet sur 0…7, le piège des cubes, puis le cas général m ≤ 9 ; enfin le coloriage du 10-cube
s = lambda n: bin(n).count('1') % 2
w = '0'
for _ in range(5): w = w + ''.join('1' if c == '0' else '0' for c in w)
v = '0'
for _ in range(5): v = ''.join('01' if c == '0' else '10' for c in v)
print(w == v == ''.join(str(s(n)) for n in range(32)), w[:16])# True 0110100110010110
print(all(s(2*n) == s(n) and s(2*n + 1) == 1 - s(n) for n in range(10**4)))# True
c = [1]
for k in range(6):
    d = 2**k; c = [(c[i] if i < len(c) else 0) - (c[i - d] if 0 <= i - d < len(c) else 0) for i in range(len(c) + d)]
print(c == [1 - 2*s(n) for n in range(64)])# True
print([n for n in range(16) if s(n) == 0], [n for n in range(16) if s(n)])# [0, 3, 5, 6, 9, 10, 12, 15] [1, 2, 4, 7, 8, 11, 13, 14]
print([(k, sum(n**k for n in range(8) if s(n) == 0), sum(n**k for n in range(8) if s(n))) for k in range(4)])# [(0, 4, 4), (1, 14, 14), (2, 70, 70), (3, 368, 416)]
print(all(sum(n**k * (1 - 2*s(n)) for n in range(2**m)) == 0 for m in range(1, 10) for k in range(m)), sum(n**3 * (1 - 2*s(n)) for n in range(16)))# True 0
print(all(s(n) != s(n ^ (1 << i)) for n in range(2**10) for i in range(10)))# True
L·101zéro factorielle
\(0!\)
=
\(1\)

par convention, mais une convention forcée par cinq raisons qui concordent. D'abord, le produit vide vaut 1, comme la somme vide vaut 0 : multiplier par « rien » ne change rien. Ensuite, \(n!=n\cdot(n-1)!\) en \(n=1\) impose \(1=1\cdot0!\). La fonction Gamma, qui prolonge la factorielle par \(n!=\Gamma(n+1)\), donne \(\Gamma(1)=\int_0^\infty e^{-t}\,dt=1\). Il y a une seule façon de ranger zéro objet : ne rien faire. Enfin, les formules restent justes : \(\binom n0=\frac{n!}{0!\,n!}=1\), et \(e=\sum_{n\geq0}\frac1{n!}\) commence par \(\frac1{0!}=1\) (XI·1). À l'inverse, \((-1)!\) n'existe pas : \(\Gamma\) a un pôle en 0, et \(0!=1\cdot(-1)!\) n'a pas de solution.

sorte loifamille comptage ; Gamma
# les trois zéros de Python : 0!, le produit vide, les rangements de rien ; n! = n(n−1)! et Γ(1) ; le binôme et e ; puis le pôle de Γ en 0
from math import factorial, comb, prod
from itertools import permutations
from mpmath import mp, mpf, gamma, quad, exp, inf, nsum, e, factorial as fact
mp.dps = 25
print(factorial(0), prod([]), len(list(permutations([]))))# 1 1 1
print(factorial(1) // 1, gamma(1), quad(lambda t: exp(-t), [0, inf]))# 1 1.0 1.0
print([comb(n, 0) for n in range(6)], all(factorial(n + 1) // (n + 1) == factorial(n) for n in range(60)))# [1, 1, 1, 1, 1, 1] True
print(nsum(lambda n: 1/fact(n), [0, inf]), e)# 2.718281828459045235360287 2.718281828459045235360287
print(abs(gamma(mpf(10)**-12)) > 10**11)# True
L·102les séries génératrices des suites périodiques
\(\sum_{n\geq0}a_n\,z^{n}\)
=
\(\frac{a_0+a_1z+\dots+a_{p-1}z^{p-1}}{1-z^{p}}\)

pour toute suite de période \(p\) et \(|z|<1\). On multiplie le bloc d'une période par \(1+z^{p}+z^{2p}+\dots=\frac1{1-z^{p}}\) (L·87), ce qui le recopie indéfiniment. Exemples : 1, 1, 1, 0 donne \(\frac{1+z+z^{2}}{1-z^{4}}\) ; 1, 1, 1, 1, 1, 0 donne \(\frac{1+z+z^{2}+z^{3}+z^{4}}{1-z^{6}}\). En général, \(k\) uns suivis d'un 0 donnent \(\frac{1+z+\dots+z^{k-1}}{1-z^{k+1}}\). Multiplier en haut et en bas par \(-1\) n'y change rien : \(\frac{-z^{2}-z-1}{z^{4}-1}\) est la même fraction. Piège : pour 1, 1, 0, la bonne fraction est \(\frac{1+z}{1-z^{3}}\). La fraction \(\frac{1+z+z^{2}+z^{3}}{1-z^{5}}\) donnerait 1, 1, 1, 1, 0. Second piège, le décalage : \(a_n=n^{2}\bmod3\) commence en \(n=0\) par un 0, la suite est 0, 1, 1, 0, 1, 1…, et sa série est \(\frac{z+z^{2}}{1-z^{3}}\). Le produit de Thue–Morse (L·100) est l'exemple opposé : une suite jamais périodique, dont la série est un produit infini.

sorte loifamille séries ; suites périodiques
# tes deux cas justes ; la bonne fraction de 1, 1, 0 et celle de ta feuille ; le décalage de n² mod 3 ; puis 40 périodes tirées au hasard
from sympy import symbols, series
import random
z = symbols('z')
coef = lambda f, N: [int(series(f, z, 0, N).removeO().coeff(z, k)) for k in range(N)]
print(coef((1 + z + z**2) / (1 - z**4), 8), coef((1 + z + z**2 + z**3 + z**4) / (1 - z**6), 12))# [1, 1, 1, 0, 1, 1, 1, 0] [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0]
print(coef((1 + z) / (1 - z**3), 9), coef((1 + z + z**2 + z**3) / (1 - z**5), 10))# [1, 1, 0, 1, 1, 0, 1, 1, 0] [1, 1, 1, 1, 0, 1, 1, 1, 1, 0]
print(coef((z + z**2) / (1 - z**3), 9) == [n**2 % 3 for n in range(9)])# True
random.seed(1)
blocs = [[random.randint(-5, 5) for _ in range(random.randint(1, 6))] for _ in range(40)]
print(all(coef(sum(a * z**i for i, a in enumerate(b)) / (1 - z**len(b)), 3*len(b)) == (b * 3) for b in blocs))# True
L·103η prolonge ζ
\(\zeta(s)\)
=
\(\frac{\eta(s)}{1-2^{1-s}}\)

où \(\eta(s)=1-\frac1{2^{s}}+\frac1{3^{s}}-\frac1{4^{s}}+\cdots\) est la fonction êta de Dirichlet. La formule vaut pour \(\operatorname{Re}s>0\), sauf en \(s=1\). La preuve tient en une ligne : \(A-B+C-D+\cdots=(A+B+C+D+\cdots)-2(B+D+\cdots)\), et les termes pairs forment \(\frac1{2^{s}}\zeta(s)\), d'où \(\eta=(1-2^{1-s})\,\zeta\) (II·3). L'intérêt : la série de \(\zeta\) ne converge que pour \(\operatorname{Re}s>1\), alors que celle de \(\eta\), grâce à ses signes alternés, converge jusqu'à \(\operatorname{Re}s>0\). La formule prolonge donc \(\zeta\). En \(s=\frac12\), \(1+\frac1{\sqrt2}+\frac1{\sqrt3}+\cdots\) diverge, mais \(\eta(\frac12)=0{,}6048986\ldots\) donne \(\zeta(\frac12)=\frac{0{,}6049\ldots}{1-\sqrt2}=-1{,}4603545\ldots\) En \(s=1\), le dénominateur s'annule : \(\zeta\) y a son pôle, tandis que \(\eta(1)=\ln2\) (I·1). Piège : en dessous de 0, ni la série de \(\zeta\) ni celle de \(\eta\) ne converge. \(\zeta(0)\) n'est pas \(1+1+1+\cdots\), et \(\zeta(-1)\) n'est pas \(1+2+3+\cdots\) : ces sommes sont infinies. Pourtant, avec les sommes d'Abel, \(\eta(0)=1-1+1-\cdots=\frac12\) (Grandi, L·87) et \(\eta(-1)=1-2+3-\cdots=\frac14\). La formule donne alors \(\zeta(0)=\frac{1/2}{1-2}=-\frac12\) et \(\zeta(-1)=\frac{1/4}{1-4}=-\frac1{12}\), les vraies valeurs du prolongement (L·20). Le fameux « \(1+2+3+\cdots=-\frac1{12}\) » n'est donc pas une somme : c'est la valeur que \(\zeta\), prolongée, prend en \(-1\).

sorte loifamille valeurs de ζ ; prolongement
# 30 points complexes avec 0 < Re s < 4 ; ζ(½) par la série convergente de η ; η(1) = ln 2 ; les sommes d'Abel de 1 − 1 + 1 … et 1 − 2 + 3 … ; ζ(0) et ζ(−1) ; puis les vraies sommes partielles de 1 + 2 + 3 …
from mpmath import mp, mpf, mpc, zeta, nsum, inf, sqrt, log, nstr
import random
mp.dps = 25
random.seed(1)
eta = lambda s: nsum(lambda n: (-1)**(n + 1) / n**s, [1, inf])
points = [mpc(random.uniform(0.1, 4), random.uniform(-15, 15)) for _ in range(30)]
print(nstr(max(abs(eta(s) / (1 - 2**(1 - s)) - zeta(s)) for s in points), 3))# 2.66e-26
print(nstr(eta(mpf(1)/2), 15), nstr(eta(mpf(1)/2) / (1 - sqrt(2)), 15), nstr(zeta(mpf(1)/2), 15))# 0.60489864342163 -1.46035450880959 -1.46035450880959
print(nstr(eta(1), 15), nstr(log(2), 15))# 0.693147180559945 0.693147180559945
abel = lambda f, x: nsum(lambda n: f(n) * x**n, [0, inf])
print([nstr(abel(lambda n: (-1)**n, x), 8) for x in (mpf('0.99'), mpf('0.999999'))], [nstr(abel(lambda n: (-1)**n * (n + 1), x), 8) for x in (mpf('0.99'), mpf('0.999999'))])# ['0.50251256', '0.50000025'] ['0.25251888', '0.25000025']
print(nstr((mpf(1)/2) / (1 - 2), 10), nstr(zeta(0), 10), nstr((mpf(1)/4) / (1 - 4), 10), nstr(zeta(-1), 10))# -0.5 -0.5 -0.08333333333 -0.08333333333
print([sum(range(1, N + 1)) for N in (10, 100, 1000)])# [55, 5050, 500500]
L·104les diviseurs d'une période du PPCM
\(\sum_{k}k\,T(n,k)\)
=
\(\operatorname{ppcm}(1,\dots,n)\cdot H_n\)

où \(T(n,k)\) compte les entiers d'une période \(1,\dots,\operatorname{ppcm}(1,\dots,n)\) qui ont exactement \(k\) diviseurs parmi \(1,\dots,n\) (A096180). La raison : chaque \(j\leq n\) divise exactement \(\operatorname{ppcm}/j\) entiers de la période. En sommant sur \(j\), on compte chaque couple (entier, diviseur), d'où \(\operatorname{ppcm}\cdot(1+\frac12+\dots+\frac1n)\). En moyenne, un entier a donc \(H_n\approx\ln n+\gamma\) diviseurs parmi les \(n\) premiers entiers. Deux bords : \(\sum_kT(n,k)=\operatorname{ppcm}(1,\dots,n)\) (A003418), et la première colonne, celle des entiers qui n'ont que 1 comme diviseur, vaut \(\varphi(\operatorname{ppcm})\) (A217863). La même structure se cache dans le carré de la matrice des moyennes \(M_{ij}=\frac1i\) pour \(j\leq i\) (A027446). Sa ligne \(n\), mise au plus petit dénominateur commun, commence par \(\operatorname{ppcm}\cdot H_n\) (A025529 : 1, 3, 11, 25, 137…) et \(\operatorname{ppcm}\cdot(H_n-1)\) (A027457), dont la différence redonne le PPCM. Enfin, puisque chaque \(\operatorname{ppcm}/k\) est entier, \(\sum_{k=2}^{n}e^{2i\pi\operatorname{ppcm}/k}=n-1\). Piège : en nombres flottants ordinaires, cette identité exacte échoue dès \(n=25\), où le PPCM atteint \(2{,}7\times10^{10}\) et l'angle perd ses décimales.

sorte loifamille PPCM ; diviseurs
# T(n, k) compté sur une période, n ≤ 12 : somme, moyenne H_n, première colonne φ ; la matrice des moyennes jusqu'à n = 59 ; puis la somme d'exponentielles, en flottants puis en 60 chiffres
from math import lcm
from functools import reduce
from fractions import Fraction as Fr
from sympy import totient
import cmath
from mpmath import mp, mpf, expjpi
L = lambda n: reduce(lcm, range(1, n + 1), 1)
H = lambda n: sum(Fr(1, k) for k in range(1, n + 1))
def ligne(n):                                    # T(n, k), par la définition, sur une période du PPCM
    v = [0]*(n + 1)
    for m in range(1, L(n) + 1): v[sum(1 for j in range(1, n + 1) if m % j == 0)] += 1
    return v[1:]
lignes = {n: ligne(n) for n in range(1, 13)}
print(lignes[5], lignes[6])   # [16, 20, 16, 7, 1] [16, 20, 12, 6, 5, 1]
print(all(sum(T) == L(n) and sum((k + 1)*t for k, t in enumerate(T)) == L(n)*H(n) and T[0] == totient(L(n)) for n, T in lignes.items()))# True
def moy(n):                                      # ligne n du carré de la matrice des moyennes, au dénominateur commun
    r = [sum(Fr(1, n*m) for m in range(j, n + 1)) for j in range(1, n + 1)]
    return [int(x * reduce(lcm, [y.denominator for y in r])) for x in r]
print([moy(n)[0] for n in range(1, 8)], [moy(n)[1] for n in range(2, 8)])# [1, 3, 11, 25, 137, 147, 1089] [1, 5, 13, 77, 87, 669]
print(all(moy(n)[0] - moy(n)[1] == L(n) for n in range(2, 60)))# True
flottant = lambda n: abs(sum(cmath.exp(2j*cmath.pi*L(n)/k) for k in range(2, n + 1)) - (n - 1))
mp.dps = 60
exact = lambda n: abs(sum(expjpi(2*mpf(L(n))/k) for k in range(2, n + 1)) - (n - 1))
print([f"{flottant(n):.0e}" for n in (10, 24, 25, 30)], max(exact(n) for n in range(3, 40)) < 1e-40)# ['5e-13', '7e-07', '1e-05', '7e-04'] True
L·105les diviseurs premiers d'une période de la primorielle
\(\sum_{k=0}^{n}T(n,k)\,x^{k}\)
=
\(\prod_{i=1}^{n}\bigl(x+p_i-1\bigr)\)

où \(T(n,k)\) compte les entiers d'une période \(1,\dots,p_1p_2\cdots p_n\) qui sont divisibles par exactement \(k\) des \(n\) premiers nombres premiers (A096294). La raison : d'après le théorème chinois, sur une période de la primorielle, les restes modulo \(p_1,\dots,p_n\) sont indépendants. Chaque premier \(p\) divise donc 1 classe sur \(p\), marquée par \(x\), et laisse les \(p-1\) autres classes, marquées par 1. Le produit des facteurs \((x+p-1)\) fait le compte. Exemple : \((x+1)(x+2)(x+4)=x^{3}+7x^{2}+14x+8\). En \(x=1\), on retrouve la primorielle. Le terme constant est \(\prod(p_i-1)=\varphi(p_n\#)\) (A005867), d'où \(A005867(n)/A005867(n-1)=p_n-1\). La deuxième colonne (A078456 : 1, 3, 14, 92, 968…) suit \(a(n)=(p_n-1)\,a(n-1)+\prod_{i

sorte loifamille nombres premiers ; primorielle
# T(n, k) compté sur une période, n ≤ 6, contre le produit ; somme et terme constant ; la récurrence de la deuxième colonne ; ses quotients ; puis la moyenne Σ 1/p
from math import prod
from fractions import Fraction as Fr
from sympy import primerange, prime, totient
premiers = lambda n: list(primerange(2, prime(n) + 1))
def compte(n):                                   # T(n, k), par la définition, sur une période de la primorielle
    P = premiers(n); v = [0]*(n + 1)
    for m in range(1, prod(P) + 1): v[sum(1 for p in P if m % p == 0)] += 1
    return v
def poly(n):                                     # coefficients de (x + 1)(x + 2)(x + 4)…(x + p_n − 1)
    c = [1]
    for p in premiers(n): c = [(c[i] if i < len(c) else 0)*(p - 1) + (c[i - 1] if i else 0) for i in range(len(c) + 1)]
    return c
print(compte(4), poly(4))     # [48, 92, 56, 13, 1] [48, 92, 56, 13, 1]
print(all(compte(n) == poly(n) for n in range(1, 7)))# True
print(all(sum(poly(n)) == prod(premiers(n)) and poly(n)[0] == totient(prod(premiers(n))) for n in range(1, 15)))# True
print(all(poly(n + 1)[1] == (prime(n + 1) - 1)*poly(n)[1] + poly(n)[0] for n in range(1, 30)))# True
print([poly(n + 1)[1] // poly(n)[1] for n in range(1, 13)], [prime(n + 1) - 1 for n in range(1, 13)])# [3, 4, 6, 10, 12, 16, 18, 22, 28, 30, 36, 40] [2, 4, 6, 10, 12, 16, 18, 22, 28, 30, 36, 40]
print(all(Fr(sum(k*c for k, c in enumerate(poly(n))), sum(poly(n))) == sum(Fr(1, p) for p in premiers(n)) for n in range(1, 30)))# True
L·106le gaz de primons
\(Z(\beta)=\sum_{\text{états}}e^{-\beta E}\)
=
\(\zeta(\beta)=\prod_p\frac{1}{1-p^{-\beta}}\)

pour un gaz imaginaire de bosons dont les seules énergies individuelles possibles sont \(\ln2,\ln3,\ln5,\ln7\ldots\), une par nombre premier (Julia, Spector, 1990), à la température inverse \(\beta>1\). Un état du gaz dit combien de particules occupent chaque niveau. Par exemple, deux particules en \(\ln2\) et une en \(\ln5\) ont l'énergie \(\ln(2\cdot2\cdot5)=\ln20\). Par la factorisation unique, chaque état correspond à exactement un entier \(n\), d'énergie \(\ln n\). La fonction de partition vaut donc \(\sum_n n^{-\beta}=\zeta(\beta)\), et chaque facteur du produit d'Euler (L·47) est la contribution d'un niveau premier. L'énergie moyenne est \(\langle E\rangle=-\frac{d\ln Z}{d\beta}=-\frac{\zeta'(\beta)}{\zeta(\beta)}=\sum_n\frac{\Lambda(n)}{n^{\beta}}\) (L·30). Mode par mode, c'est la loi de Bose–Einstein : \(\langle E\rangle=\sum_p\frac{\ln p}{p^{\beta}-1}\). Quand \(\beta\to1\), le pôle de \(\zeta\) fait exploser l'énergie, comme \(\frac1{\beta-1}\) : on ne peut pas chauffer ce gaz au-delà de \(\beta=1\). C'est une température de Hagedorn. Version fermions, où chaque niveau porte au plus une particule : \(\prod_p(1+p^{-\beta})=\frac{\zeta(\beta)}{\zeta(2\beta)}\), la somme sur les entiers sans facteur carré, soit \(\frac{15}{\pi^{2}}\) en \(\beta=2\). En comptant chaque état avec le signe \((-1)^{\text{nombre de particules}}\), on retrouve \(1/\zeta=\sum\mu(n)/n^{\beta}\) (VIII·2). Les températures complexes où \(Z\) s'annule, les zéros de Fisher qui signalent les transitions de phase, sont, via le prolongement de \(\zeta\) (L·103), exactement les zéros de Riemann. Ce gaz n'existe pas dans la nature : personne ne sait fabriquer des niveaux d'énergie en \(\ln p\). Mais il traduit Riemann en physique statistique (C·7). Son spectre d'absorption et d'émission : L·107.

sorte loifamille valeurs de ζ ; physique statistique
# les 10 000 premiers états du gaz sont exactement les entiers 1 à 10 000 ; Z(2) par le produit sur les premiers < 10⁵ ; l'énergie moyenne, par −ζ′/ζ puis par Bose–Einstein ; l'explosion vers β = 1 ; puis le gaz de fermions
from math import log
from sympy import primerange
from mpmath import mp, mpf, zeta, diff, pi, nstr
mp.dps = 25
P = list(primerange(2, 10**5))
def etats(N, i=0, n=1):                          # un état = un multiensemble de premiers ; son « nom » = leur produit
    yield n
    for j in range(i, len(P)):
        if n * P[j] > N: break
        yield from etats(N, j, n * P[j])
print(sorted(etats(10**4)) == list(range(1, 10**4 + 1)))# True
b, Z, F = mpf(2), mpf(1), mpf(1)
for p in P: Z /= 1 - mpf(p)**-b; F *= 1 + mpf(p)**-b
print(nstr(Z, 10), nstr(zeta(b), 10))# 1.644932747 1.644934067
E = lambda x: -diff(zeta, x) / zeta(x)
print(nstr(E(b), 10), nstr(sum(mpf(log(p)) / (mpf(p)**b - 1) for p in P), 10))# 0.5699609931 0.5699510101
print([nstr((x - 1) * E(x), 8) for x in (mpf(2), mpf('1.1'), mpf('1.001'))])# ['0.56996099', '0.94410364', '0.99942297']
print(nstr(F, 10), nstr(zeta(2) / zeta(4), 10), nstr(15 / pi**2, 10))# 1.519816535 1.519817755 1.519817755
L·107le spectre du gaz de primons
\(I_{\text{abs}}\bigl(\ln\tfrac ab\bigr)\)
=
\(b^{-\beta}\)

pour le gaz de primons (L·106) à l'équilibre, à la température inverse \(\beta>1\), en supposant toutes les transitions également couplées. Un état est un entier \(n\), d'énergie \(\ln n\), présent avec la probabilité \(n^{-\beta}/\zeta(\beta)\). Passer de \(n\) à \(m\) absorbe ou émet un photon d'énergie \(\ln\frac mn\) : les raies sont les logarithmes des fractions \(\frac ab\), écrites irréductibles. Si une seule particule saute à la fois, d'un niveau \(p\) vers un niveau \(q\), les raies se réduisent à \(\ln\frac qp\) pour deux premiers. Si toutes les réorganisations sont permises, elles remplissent l'axe de façon dense. Pour absorber \(\ln\frac ab\), l'état de départ doit contenir le facteur \(b\), donc être un multiple de \(b\). Ces états pèsent \(\sum_k(kb)^{-\beta}/\zeta(\beta)=b^{-\beta}\). L'émission de la même raie part d'un multiple de \(a\) et pèse \(a^{-\beta}\). Le rapport émission/absorption vaut \((a/b)^{-\beta}=e^{-\beta\,\Delta E}\) : c'est le bilan détaillé de Boltzmann. Les niveaux premiers sont indépendants, comme les modes d'un gaz de bosons. On peut donc simuler le gaz en tirant pour chaque \(p\) une occupation géométrique de raison \(p^{-\beta}\). Le trésor est ailleurs : par la formule explicite de Riemann–Weil, les raies \(\ln p,\ln p^{2},\ldots\), pondérées par \(\Lambda(n)/\sqrt n\), sont la transformée de Fourier des zéros de Riemann. La somme \(-\sum_n\frac{\Lambda(n)}{\sqrt n}\cos(t\ln n)\) présente des pics exactement aux hauteurs \(\gamma=14{,}13\ldots,\ 21{,}02\ldots,\ 25{,}01\ldots\) C'est l'analogue de la formule des traces de Gutzwiller en chaos quantique, où les longueurs des orbites périodiques (ici les \(\ln p\)) déterminent les niveaux d'énergie (ici les \(\gamma\)) : la lecture de Berry de l'hypothèse de Riemann (C·7).

sorte loifamille valeurs de ζ ; physique statistique
# 100 000 états tirés à β = 2 : absorption b^−β, bilan détaillé (a/b)^−β ; les raies ln(q/p) des petits premiers ; puis la formule explicite sur les puissances de premiers jusqu'à 10⁶, dont les pics tombent sur les dix premiers zéros
import random, math
import numpy as np
from sympy import primerange
from fractions import Fraction as Fr
from mpmath import zetazero
random.seed(1)
beta, P = 2.0, list(primerange(2, 2000))
def tirage():                                    # chaque niveau p : occupation géométrique de raison p^-β
    n = 1
    for p in P:
        while random.random() < p**-beta: n *= p
    return n
E = [tirage() for _ in range(100000)]
part = lambda b: sum(1 for n in E if n % b == 0) / len(E)
print([(b, round(part(b), 4), round(b**-beta, 4)) for b in (2, 3, 5, 6, 12)])# [(2, 0.2509, 0.25), (3, 0.1106, 0.1111), (5, 0.0393, 0.04), (6, 0.0277, 0.0278), (12, 0.0068, 0.0069)]
print([(f'{a}/{b}', round(part(a) / part(b), 3), round((a / b)**-beta, 3)) for a, b in ((3, 2), (5, 3), (7, 5))])# [('3/2', 0.441, 0.444), ('5/3', 0.356, 0.36), ('7/5', 0.524, 0.51)]
print(sorted({str(Fr(q, p)) for p in (2, 3, 5, 7) for q in (2, 3, 5, 7) if q > p}, key=lambda r: float(Fr(r))))# ['7/5', '3/2', '5/3', '7/3', '5/2', '7/2']
X = 10**6
lam = np.zeros(X + 1)
for p in primerange(2, X + 1):
    q = p
    while q <= X: lam[q] = math.log(p); q *= p
n = np.nonzero(lam)[0]; w = lam[n] / np.sqrt(n) * (1 - np.log(n) / math.log(X))
t = np.arange(8, 50, 0.005)
S = -np.array([np.sum(w * np.cos(tt * np.log(n))) for tt in t])
pics = [round(float(t[i]), 2) for i in range(1, len(t) - 1) if S[i] > S[i - 1] and S[i] > S[i + 1] and S[i] > 0.25 * S.max()]
print(pics)                   # [14.13, 21.01, 25.01, 30.43, 32.94, 37.59, 40.92, 43.33, 48.01, 49.77]
print([round(float(zetazero(k).imag), 2) for k in range(1, 11)])# [14.13, 21.02, 25.01, 30.42, 32.94, 37.59, 40.92, 43.33, 48.01, 49.77]
L·108le tri de la patiencecité · Baik, Deift, Johansson 1999
\(\#\{\text{tas}\}\)
=
\(L(\sigma)\)

où \(L(\sigma)\) est la longueur de la plus longue sous-suite croissante d'une permutation \(\sigma\). Le jeu : on retourne les cartes une à une ; chaque carte va sur le tas le plus à gauche dont la carte du dessus est plus haute qu'elle, et ouvre un nouveau tas à droite si aucun ne convient. Le nombre de tas est exactement \(L(\sigma)\). En effet, une suite croissante ne peut jamais poser deux cartes sur le même tas, et en suivant pour chaque carte le dessus du tas voisin de gauche au moment de sa pose, on remonte une suite croissante qui traverse tous les tas. Le nombre \(T(n,k)\) de permutations à \(k\) tas forme le triangle A047874 : 1, 4, 1 pour \(n=3\) ; 1, 13, 9, 1 pour \(n=4\)… Par la correspondance de Robinson–Schensted, \(T(n,k)=\sum f_\lambda^{2}\), sur les partitions \(\lambda\) de \(n\) dont la première ligne vaut \(k\), où \(f_\lambda\) se calcule par la formule des équerres. Deux bords : \(T(n,2)=C_n-1\), avec \(C_n\) le nombre de Catalan, car les permutations à au plus deux tas sont celles qui évitent le motif 123 ; et \(T(n,n-1)=(n-1)^{2}\). Le problème d'Ulam (1961) demandait la taille typique de \(L\). La réponse : \(L\approx2\sqrt n\) (Vershik–Kerov, Logan–Shepp, 1977), avec 11 ou 12 tas pour un jeu de 52 cartes. Baik, Deift et Johansson (1999) ont trouvé la loi des fluctuations : \((L-2\sqrt n)/n^{1/6}\) suit la loi de Tracy–Widom GUE, de moyenne \(-1{,}7711\) et d'écart type \(0{,}9018\), celle de la plus grande valeur propre d'une grande matrice aléatoire hermitienne. À taille finie, la convergence est lente : avec 10 000 cartes, on mesure encore une moyenne voisine de −1,65. C'est la même famille de lois que les écarts entre zéros de Riemann et que les bus de Cuernavaca : un jeu de cartes sur les entiers qui se comporte comme un système chaotique (C·2, L·107). Les tas sont des piquets de Hanoï (L·110), et les tas d'une permutation sont les marcheurs vicieux d'un aller-retour (L·109). Variantes : jeux à cartes répétées (L·111), règle des premiers (L·113), détecteur d'ordre (L·114).

sorte loifamille comptage ; matrices aléatoires
# le jeu contre la force brute sur 2 000 mélanges ; les lignes 4 et 7 du triangle ; Robinson–Schensted contre l'énumération jusqu'à 8, puis la ligne 10 ; Catalan et (n − 1)² ; enfin 2 000 parties de 52 puis 10 000 cartes : moyenne des tas, puis moyenne et écart type de (L − 2√n)/n^{1/6}, contre −1,771 et 0,902 pour Tracy–Widom
import bisect, random, math
from itertools import permutations
from math import factorial, comb
def tas(p):                                      # le jeu : on ne garde que la carte du dessus de chaque tas
    dessus = []
    for c in p:
        i = bisect.bisect_left(dessus, c)
        if i == len(dessus): dessus.append(c)
        else: dessus[i] = c
    return len(dessus)
def plsc(p):                                     # plus longue sous-suite croissante, par force brute quadratique
    m = [1]*len(p)
    for i in range(len(p)):
        for j in range(i):
            if p[j] < p[i]: m[i] = max(m[i], m[j] + 1)
    return max(m)
random.seed(1)
print(all(tas(p) == plsc(p) for p in (random.sample(range(60), 60) for _ in range(2000))))# True
def ligne(n):
    c = [0]*(n + 1)
    for p in permutations(range(n)): c[tas(p)] += 1
    return c[1:]
print(ligne(4), ligne(7))     # [1, 13, 9, 1] [1, 428, 2332, 1821, 421, 36, 1]
def partitions(n, m=None):
    m = m or n
    if n == 0: yield []; return
    for k in range(min(n, m), 0, -1):
        for r in partitions(n - k, k): yield [k] + r
def f(lam):                                      # formule des équerres
    col = [sum(1 for r in lam if r > j) for j in range(lam[0])]
    return factorial(sum(lam)) // math.prod(lam[i] - j + col[j] - i - 1 for i in range(len(lam)) for j in range(lam[i]))
rsk = lambda n: [sum(f(l)**2 for l in partitions(n) if l[0] == k) for k in range(1, n + 1)]
print(all(rsk(n) == ligne(n) for n in range(1, 9)), rsk(10))# True [1, 16795, 569794, 1604098, 1100902, 296326, 38281, 2521, 81, 1]
print(all(rsk(n)[1] == comb(2*n, n)//(n + 1) - 1 and rsk(n)[n - 2] == (n - 1)**2 for n in range(3, 16)))# True
def parties(n):                                 # 2 000 parties de n cartes
    v = [(tas(random.sample(range(n), n)) - 2*math.sqrt(n)) / n**(1/6) for _ in range(2000)]
    m = sum(v)/len(v); return n, round(2*math.sqrt(n) + m*n**(1/6), 2), round(m, 3), round(math.sqrt(sum((x - m)**2 for x in v)/len(v)), 3)
print(parties(52))            # (52, 11.57, -1.479, 0.743)
print(parties(10**4))         # (10000, 192.36, -1.645, 0.889)
L·109les marcheurs vicieux
\(\#\{\text{pastèques de }p\text{ marcheurs en }n\text{ pas}\}\)
\(=\)
\(\sum_{k=0}^{n}\prod_{j=0}^{p-1}\frac{\binom{n+j}{k}}{\binom{k+j}{k}}\)

pour le modèle de Fisher (1984) : \(p\) marcheurs partent des sites 0, 2, 4…, chacun fait un pas \(\pm1\) à chaque instant, et deux marcheurs qui se rencontrent s'annihilent ; on ne compte que les histoires sans rencontre. Une pastèque finit avec les marcheurs côte à côte (écarts 2), à n'importe quelle hauteur ; une étoile finit n'importe où. La somme de Hoggatt ci-dessus compte les pastèques : Catalan\((n+1)\) pour 2 marcheurs, les nombres de Baxter (A001181) pour 3, A005362 pour 4 (Essam et Guttmann, 1995). Les étoiles : \(\binom{2n+1}{n}\) (A001700) pour 2 marcheurs, \(2^{n}C_{n+1}\) (A003645) pour 3, \(\frac{(2m)!\,(2m+1)!}{m!^{2}(m+1)!\,(m+2)!}\) avec \(m=n+1\) (A000356) pour 4. Les pastèques à extrémités fixées, où chacun revient exactement à son point de départ, se calculent par le lemme de Lindström–Gessel–Viennot : c'est le déterminant des nombres de chemins individuels, soit \(\frac{(2n)!(2n+1)!}{n!^{2}(n+1)!^{2}}\) pour 2 marcheurs en \(2n\) pas (A000891). Deux bijections éclairent le cas de deux marcheurs. En entrelaçant les pas du marcheur du haut avec les pas inversés de celui du bas, \(U\,q_1p_1'\,q_2p_2'\cdots q_np_n'\,D\), une 2-pastèque devient un chemin de Dyck, dont la hauteur mesure l'écart. Et deux marcheurs partis à distance \(2i\) qui se rencontrent pour la première fois au pas \(n\) sont au nombre de \(\frac in\binom{2n}{n-i}\), le nombre de bulletins du problème du scrutin de Bertrand (1887). Survie : la probabilité que \(p\) marcheurs vivent encore au temps \(n\) décroît comme \(n^{-p(p-1)/4}\), et les pastèques comme \(n^{-p^{2}/2}\) relativement à toutes les marches. Trois marcheurs équivalent à un seul marcheur dans un coin de 60°, où la survie décroît comme \(n^{-\pi/(2\theta)}=n^{-3/2}\). Dans la variante « à tour de rôle », où un seul marcheur avance d'un pas à chaque instant, les positions sont les longueurs des lignes d'un tableau de Young. Les étoiles de 3 marcheurs sont alors les nombres de Motzkin (A001006), et un aller-retour de \(p\) marcheurs en \(n\) pas est une permutation de \(n\) cartes qui fait au plus \(p\) tas au tri de la patience (L·108). Vus de loin, les marcheurs se repoussent comme les valeurs propres d'une matrice aléatoire. Variante non markovienne : les marcheurs accélérés (C·8).

sorte loifamille comptage ; matrices aléatoires
# pastèques de 2, 3 et 4 marcheurs contre Hoggatt et Baxter ; étoiles contre A001700, A003645 et A000356 ; extrémités fixées par Lindström–Gessel–Viennot ; la bijection vers les chemins de Dyck ; les bulletins de Bertrand ; la survie entre 40 et 80 pas ; enfin Motzkin et le pont avec la patience
from itertools import product, permutations
from math import comb, factorial as f, log
from fractions import Fraction as Fr
from sympy import Matrix
import bisect
cat = lambda n: comb(2*n, n) // (n + 1)
def histoires(p, N, fin):                        # modèle de Fisher : tous les marcheurs bougent à chaque pas
    etats = {tuple(2*i for i in range(p)): 1}; out = []
    for _ in range(N):
        nv = {}
        for x, c in etats.items():
            for d in product((-1, 1), repeat=p):
                y = tuple(a + b for a, b in zip(x, d))
                if all(y[i] < y[i + 1] for i in range(p - 1)): nv[y] = nv.get(y, 0) + c
        etats = nv; out.append(sum(c for x, c in etats.items() if fin(x)))
    return out
cote = lambda x: all(x[i + 1] - x[i] == 2 for i in range(len(x) - 1))
def S(d, n):                                     # somme de Hoggatt
    tot = Fr(0)
    for k in range(n + 1):
        t = Fr(1)
        for j in range(d): t *= Fr(comb(n + j, k), comb(k + j, k))
        tot += t
    return int(tot)
baxter = lambda m: sum(comb(m + 1, k - 1) * comb(m + 1, k) * comb(m + 1, k + 1) for k in range(1, m + 1)) // (comb(m + 1, 1) * comb(m + 1, 2))
P = {p: histoires(p, N, cote) for p, N in ((2, 12), (3, 10), (4, 8))}
print([P[p][:6] for p in (2, 3, 4)])# [[2, 5, 14, 42, 132, 429], [2, 6, 22, 92, 422, 2074], [2, 7, 32, 177, 1122, 7898]]
print(all(P[p][n - 1] == S(p, n) for p in P for n in range(1, len(P[p]) + 1)), all(P[3][n - 1] == baxter(n + 1) for n in range(1, 11)))# True True
E = {p: histoires(p, N, lambda x: True) for p, N in ((2, 12), (3, 12), (4, 9))}
A356 = lambda m: f(2*m) * f(2*m + 1) // (f(m)**2 * f(m + 1) * f(m + 2))
print(all(E[2][n - 1] == comb(2*n + 1, n) and E[3][n - 1] == 2**n * cat(n + 1) for n in range(1, 13)), all(E[4][n - 1] == A356(n + 1) for n in range(1, 10)))# True True
ch = lambda a, b, n: comb(n, (n + b - a) // 2) if (n + b - a) % 2 == 0 and abs(b - a) <= n else 0
fixe = lambda p, n: histoires(p, n, lambda x: x == tuple(2*i for i in range(p)))[-1]
print(all(Matrix(p, p, lambda i, j: ch(2*i, 2*j, 2*n)).det() == fixe(p, 2*n) for p in (2, 3) for n in range(1, 6)), [f(2*n) * f(2*n + 1) // (f(n)**2 * f(n + 1)**2) for n in range(1, 6)])# True [3, 20, 175, 1764, 19404]
inv = {1: -1, -1: 1}
haut = lambda w: [sum(w[:k]) for k in range(len(w) + 1)]
paires = [(a, b) for n in range(1, 8) for a in product((1, -1), repeat=n) for b in product((1, -1), repeat=n) if all(y >= x for x, y in zip(haut(a), haut(b))) and sum(a) == sum(b)]
dyck = {(1,) + sum(((q, inv[p]) for p, q in zip(a, b)), ()) + (-1,) for a, b in paires}
print(len(paires) == len(dyck) == sum(cat(n + 1) for n in range(1, 8)), all(min(haut(w)) >= 0 and sum(w) == 0 for w in dyck))# True True
def T(i, n):                                     # rencontre pour la première fois au pas n, départ à distance 2i
    return sum(1 for a in product((1, -1), repeat=n) for b in product((1, -1), repeat=n) if all(2*i + y > x for x, y in zip(haut(a)[:-1], haut(b)[:-1])) and haut(a)[-1] == 2*i + haut(b)[-1])
print(all(T(i, n) == Fr(i, n) * comb(2*n, n - i) == comb(2*n - 1, n - i) - (comb(2*n - 1, n - i - 1) if i < n else 0) for n in range(1, 9) for i in range(1, n + 1)))# True
pente = lambda p, fin: round(log((histoires(p, 80, fin)[-1] / 2**(80*p)) / (histoires(p, 40, fin)[-1] / 2**(40*p))) / log(2), 3)
print([(p, pente(p, lambda x: True), -p*(p - 1)/4) for p in (2, 3)])# [(2, -0.489, -0.5), (3, -1.454, -1.5)]
def tas(q):
    d = []
    for c in q:
        i = bisect.bisect_left(d, c)
        if i == len(d): d.append(c)
        else: d[i] = c
    return len(d)
def tour(p, n):                                  # à tour de rôle : un marcheur avance ; positions = lignes d'un tableau de Young
    out = {(0,)*p: 1}
    for _ in range(n):
        nv = {}
        for lam, c in out.items():
            for i in range(p):
                m = list(lam); m[i] += 1
                if all(m[j] >= m[j + 1] for j in range(p - 1)): nv[tuple(m)] = nv.get(tuple(m), 0) + c
        out = nv
    return out
print([sum(tour(3, n).values()) for n in range(1, 11)], all(sum(c*c for c in tour(p, n).values()) == sum(1 for q in permutations(range(n)) if tas(q) <= p) for p in (2, 3) for n in range(1, 8)))# [1, 2, 4, 9, 21, 51, 127, 323, 835, 2188] True
L·110les tours de Hanoï
\(\#\{\text{coups pour }n\text{ disques}\}\)
=
\(2^{n}-1\)

pour déplacer une tour de \(n\) disques d'un piquet à un autre, avec trois piquets, sans jamais poser un disque sur un plus petit (Lucas, 1883). On déplace les \(n-1\) disques du dessus, puis le grand, puis les \(n-1\) disques par-dessus, d'où \(h_n=2h_{n-1}+1\). La solution est entièrement binaire : au coup \(k\), le disque déplacé porte le numéro \(1+\nu_2(k)\), le nombre de zéros à la fin de \(k\) écrit en base 2 (1, 2, 1, 3, 1, 2, 1, 4… A001511), et la suite des états suit le code de Gray réfléchi, qui ne change qu'un chiffre binaire à chaque coup : un chemin qui visite tous les sommets de l'hypercube (L·14). Lien avec la patience (L·108) : la règle de Hanoï est celle des tas, chaque tas étant une petite tour. Si l'on reçoit les disques d'une tour dans le désordre, un par un, et qu'on doit les empiler aussitôt selon la règle, sans jamais les redéplacer, il faut exactement autant de piquets que la plus longue suite croissante, environ \(2\sqrt n\), et la stratégie gloutonne de la patience atteint ce minimum. Les deux jeux sont opposés : Hanoï fixe la place (3 piquets) et paie en temps (\(2^{n}-1\) coups) ; la patience interdit les déplacements et paie en place. Deux familles de Catalan en sortent : les permutations qu'on trie avec deux piquets en empilant tout puis en dépilant dans l'ordre sont celles sans suite croissante de longueur 3 ; celles qu'on trie avec un seul piquet, en empilant et dépilant librement, évitent le motif 231 (Knuth, 1968). Les deux familles sont différentes, mais toutes deux comptées par \(1, 2, 5, 14, 42, \ldots\)

sorte loifamille comptage ; binaire
# les coups pour 1 à 10 disques, et la règle rejouée jusqu'à 12 ; le disque du coup k ; le code de Gray sur l'hypercube de dimension 10 ; le minimum de piquets contre la patience ; puis les deux familles de Catalan, et combien elles diffèrent pour 5 cartes
import bisect
from itertools import permutations, product
from math import comb
def hanoi(n, a=0, b=2, c=1, out=None):            # liste des coups (disque, départ, arrivée)
    if out is None: out = []
    if n: hanoi(n - 1, a, c, b, out); out.append((n, a, b)); hanoi(n - 1, c, b, a, out)
    return out
def legal(n):                                    # rejoue les coups en vérifiant la règle
    piq = [list(range(n, 0, -1)), [], []]
    for d, a, b in hanoi(n):
        if not piq[a] or piq[a][-1] != d or (piq[b] and piq[b][-1] < d): return False
        piq[b].append(piq[a].pop())
    return piq[2] == list(range(n, 0, -1))
print([len(hanoi(n)) for n in range(1, 11)], all(legal(n) for n in range(1, 13)))# [1, 3, 7, 15, 31, 63, 127, 255, 511, 1023] True
h = [d for d, a, b in hanoi(10)]
print(h[:15], all(h[k - 1] == (k & -k).bit_length() for k in range(1, 2**10)))# [1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1] True
gray = [k ^ (k >> 1) for k in range(2**10)]
print(all(bin(gray[k] ^ gray[k - 1]).count('1') == 1 and (gray[k] ^ gray[k - 1]).bit_length() == h[k - 1] for k in range(1, 2**10)), len(set(gray)) == 2**10)# True True
def tas(p):
    d = []
    for c in p:
        i = bisect.bisect_left(d, c)
        if i == len(d): d.append(c)
        else: d[i] = c
    return len(d)
def min_piquets(p):                              # force brute : moins de piquets possible, règle de Hanoï, sans redéplacer
    for k in range(1, len(p) + 1):
        for aff in product(range(k), repeat=len(p)):
            top, ok = [None]*k, True
            for c, j in zip(p, aff):
                if top[j] is not None and top[j] < c: ok = False; break
                top[j] = c
            if ok: return k
print(all(tas(p) == min_piquets(p) for n in range(1, 7) for p in permutations(range(n))))# True
def knuth(p):                                    # un piquet, empiler et dépiler librement
    pile, att = [], 0
    for c in p:
        pile.append(c)
        while pile and pile[-1] == att: pile.pop(); att += 1
    return not pile
deux = [sum(1 for p in permutations(range(n)) if tas(p) <= 2) for n in range(1, 9)]
un = [sum(1 for p in permutations(range(n)) if knuth(p)) for n in range(1, 9)]
print(deux, un, [comb(2*n, n) // (n + 1) for n in range(1, 9)])# [1, 2, 5, 14, 42, 132, 429, 1430] [1, 2, 5, 14, 42, 132, 429, 1430] [1, 2, 5, 14, 42, 132, 429, 1430]
print(sum(1 for p in permutations(range(5)) if tas(p) <= 2 and knuth(p)), sum(1 for p in permutations(range(5)) if (tas(p) <= 2) != knuth(p)))# 11 62
L·111la patience généralisée
\(\#\{\text{mélanges de forme }\lambda\}\)
=
\(f_\lambda\,K_{\lambda\mu}\)

pour un jeu quelconque dont la valeur \(v\) figure en \(\mu_v\) exemplaires, où \(f_\lambda\) est le nombre des équerres (L·108) et \(K_{\lambda\mu}\) le nombre de Kostka : le nombre de tableaux de forme \(\lambda\) remplis avec \(\mu_1\) fois 1, \(\mu_2\) fois 2, etc., en croissant au sens large le long des lignes et strictement le long des colonnes. C'est la correspondance de Robinson–Schensted–Knuth (1970), qui envoie chaque mélange sur un couple de tableaux de même forme \(\lambda\). Un jeu « fabriqué » se décrit par des séries de longueurs \(L_1,L_2,\ldots\), chacune contenant les valeurs \(1,\ldots,L\) : la valeur \(v\) apparaît dans autant d'exemplaires qu'il y a de séries de longueur au moins \(v\), si bien que \(\mu\) est la partition conjuguée de \(L\). Le jeu réel, c'est 4 séries de 13. Il faut alors choisir une règle quand une carte tombe sur une carte de même valeur, et cette règle décide dans quel sens on lit le tableau. Égal sur égal permis : le nombre de tas est le nombre de lignes de \(\lambda\), la plus longue suite strictement croissante ; il ne dépasse jamais le nombre de valeurs distinctes. Égal sur égal interdit : c'est la longueur de la première ligne, la plus longue suite croissante au sens large ; il vaut au moins la plus grande multiplicité. Pour 52 cartes distinctes, les deux règles coïncident (11,6 tas en moyenne) ; pour le jeu réel, elles s'écartent (9,2 contre 13,6), et l'écart grandit avec les répétitions : avec 13 séries de 4, on obtient exactement 4 tas d'un côté, et une vingtaine de l'autre. Second sens de « séries croissantes cachées » : un paquet mal mélangé. Un mélange à l'américaine (modèle de Gilbert–Shannon–Reeds) laisse au plus \(2^{k}\) séries montantes après \(k\) mélanges, et la patience voit encore l'ordre jusqu'à 6 ou 7 mélanges, puis se stabilise : l'écho, en tas, du résultat de Bayer et Diaconis (1992) selon lequel il faut environ 7 mélanges pour bien battre un jeu.

sorte loifamille comptage ; tableaux de Young
# la formule de Robinson–Schensted–Knuth contre la force brute sur 8 petits jeux ; la distribution exacte pour 3 séries de 4 (les valeurs 1 à 4, chacune en 3 exemplaires) : égal permis, puis égal interdit ; puis, pour des jeux de 52 cartes, moyenne et maximum avec égal permis, moyenne et minimum avec égal interdit ; enfin les tas après k mélanges à l'américaine
import bisect, random
from itertools import permutations
from functools import lru_cache
from math import factorial, prod
from collections import Counter
random.seed(1)
def tas(p, egal_permis):                         # égal permis : la carte peut aller sur une carte de même valeur
    d = []
    for c in p:
        i = bisect.bisect_left(d, c) if egal_permis else bisect.bisect_right(d, c)
        if i == len(d): d.append(c)
        else: d[i] = c
    return len(d)
def partitions(n, m=None):
    m = m or n
    if n == 0: yield (); return
    for k in range(min(n, m), 0, -1):
        for r in partitions(n - k, k): yield (k,) + r
def f(lam):                                      # formule des équerres
    col = [sum(1 for r in lam if r > j) for j in range(lam[0])] if lam else []
    return factorial(sum(lam)) // prod(lam[i] - j + col[j] - i - 1 for i in range(len(lam)) for j in range(lam[i]))
@lru_cache(None)
def K(lam, mu):                                  # Kostka : on retire la bande horizontale de la plus grande valeur
    if not mu: return int(not lam)
    sous = []
    def bande(i, reste, nl):
        if i == len(lam):
            if reste == 0: sous.append(tuple(x for x in nl if x))
            return
        bas = lam[i + 1] if i + 1 < len(lam) else 0
        for k in range(min(reste, lam[i] - bas) + 1): bande(i + 1, reste - k, nl + [lam[i] - k])
    bande(0, mu[-1], [])
    return sum(K(x, mu[:-1]) for x in sous)
def formule(mu):
    a, b = Counter(), Counter()
    for lam in partitions(sum(mu)):
        c = f(lam) * K(lam, tuple(mu))
        if c: a[len(lam)] += c; b[lam[0]] += c
    return dict(sorted(a.items())), dict(sorted(b.items()))
def brute(mu):
    jeu = [v for v, m in enumerate(mu) for _ in range(m)]
    a, b = Counter(), Counter()
    for q in set(permutations(jeu)): a[tas(q, True)] += 1; b[tas(q, False)] += 1
    return dict(sorted(a.items())), dict(sorted(b.items()))
print(all(formule(mu) == brute(mu) for mu in [(2, 2), (3, 3), (2, 2, 2), (3, 2, 1), (2, 2, 2, 2), (4, 3, 2), (3, 3, 3), (1,)*7]))# True
print(formule((3, 3, 3, 3)))  # ({1: 1, 2: 8123, 3: 165767, 4: 195709}, {3: 462, 4: 23562, 5: 108009, 6: 135289, 7: 74569, 8: 22921, 9: 4265, 10: 489, 11: 33, 12: 1})
series = lambda L: [v for l in L for v in range(1, l + 1)]
def moyennes(L, R=4000):
    a, b = [], []
    for _ in range(R):
        q = series(L); random.shuffle(q); a.append(tas(q, True)); b.append(tas(q, False))
    return L if len(L) < 6 else f'{len(L)}x{L[0]}', round(sum(a)/R, 2), max(a), round(sum(b)/R, 2), min(b)
print([moyennes(L) for L in ([52], [26, 26], [13]*4, [4]*13, [20, 16, 10, 6])])# [([52], 11.54, 17, 11.54, 7), ([26, 26], 10.76, 15, 12.23, 8), ([13, 13, 13, 13], 9.2, 13, 13.6, 9), ('13x4', 4.0, 4, 20.07, 14), ([20, 16, 10, 6], 10.0, 14, 12.98, 8)]
def riffle(p):                                   # mélange à l'américaine (Gilbert–Shannon–Reeds)
    k = sum(random.random() < 0.5 for _ in p); g, d, out = p[:k], p[k:], []
    while g or d: out.append(g.pop(0) if random.random() < len(g) / (len(g) + len(d)) else d.pop(0))
    return out
def apres(k, R=2000):
    v = []
    for _ in range(R):
        p = list(range(52))
        for _ in range(k): p = riffle(p)
        v.append(tas(p, True))
    return round(sum(v)/R, 1)
print([(k, apres(k)) for k in (1, 2, 3, 4, 5, 6, 7, 8, 10)])# [(1, 31.3), (2, 21.2), (3, 16.3), (4, 13.9), (5, 12.8), (6, 12.1), (7, 11.9), (8, 11.7), (10, 11.6)]
L·112le codage de Gödel par les premiers
\(\ulcorner a_1a_2\cdots a_k\urcorner\)
=
\(2^{a_1}\,3^{a_2}\,5^{a_3}\cdots p_k^{\,a_k}\)

pour tout mot \(a_1a_2\cdots a_k\) écrit avec des symboles numérotés \(1,2,3,\ldots\) Gödel (1931) code ainsi chaque formule de l'arithmétique, puis chaque démonstration, qui est une suite de formules, par un seul entier. Le codage est injectif grâce à la factorisation unique : on retrouve le mot en lisant l'exposant de chaque premier, le \(k\)-ième symbole étant l'exposant de \(p_k\). Ce n'est pas une bijection : un entier dont les premiers « sautent » une place, comme \(2\cdot5=10\), ne code aucun mot. Avec ce codage, des énoncés sur les formules (« ceci est une démonstration de cela ») deviennent des énoncés sur les entiers, et Gödel peut écrire une phrase qui dit d'elle-même qu'elle n'est pas démontrable : c'est le premier théorème d'incomplétude. Lien avec le gaz de primons (L·106) : un mot est un état du gaz, avec \(a_i\) particules sur le \(i\)-ième niveau premier, et son énergie est \(\ln\ulcorner w\urcorner=\sum a_i\ln p_i\). Le gaz contient donc, sous forme d'états, toutes les phrases qu'on peut écrire. Les nombres croissent très vite : coder le mot de 10 lettres « 1111111111 » donne déjà \(6\,469\,693\,230=29\#\), la primorielle (C·6). Les mots tirés au hasard rejoignent la logique par Chaitin (années 1970) : presque tous sont incompressibles, au sens de la complexité de Kolmogorov, mais un système d'axiomes donné ne peut démontrer, pour aucun mot précis, que sa complexité dépasse une constante qui dépend du système. Presque tout est aléatoire, et presque rien ne peut être prouvé aléatoire.

sorte loifamille logique ; nombres premiers
# coder et décoder le mot 3 1 2 ; refuser 10, qui saute le premier 3 ; 3 000 mots au hasard, décodés sans erreur et sans collision ; le mot de dix 1 et la primorielle ; l'énergie du gaz de primons ; puis combien d'entiers jusqu'à 10 000 codent un mot
from sympy import prime, factorint, primorial
import random
random.seed(1)
code = lambda mot: __import__('math').prod(prime(i + 1)**a for i, a in enumerate(mot))
def decode(n):                                   # lit les exposants dans l'ordre des premiers ; refuse les trous
    f = factorint(n); mot = []
    for i in range(len(f)):
        if prime(i + 1) not in f: return None
        mot.append(f[prime(i + 1)])
    return mot
print(code([3, 1, 2]), decode(code([3, 1, 2])), decode(10))# 600 [3, 1, 2] None
mots = [[random.randint(1, 6) for _ in range(random.randint(1, 8))] for _ in range(3000)]
print(all(decode(code(m)) == m for m in mots), len({code(m) for m in mots}) == len({tuple(m) for m in mots}))# True True
print(code([1]*10), primorial(10))# 6469693230 6469693230
from math import log
print(all(abs(log(code(m)) - sum(a * log(prime(i + 1)) for i, a in enumerate(m))) < 1e-9 for m in mots[:200]))# True
print(sum(1 for n in range(2, 10001) if decode(n) is not None))# 147
L·113la patience des premiers
\(\#\{\sigma\in S_n : n\text{ tas}\}\)
=
\(\prod_{p\leq n}(n+1-p)\)

pour le tri de la patience (L·108) avec une règle en plus : une carte première ouvre toujours un nouveau tas, les autres cartes, 1 compris, suivant la règle ordinaire. Deux variantes. Règle libre : on peut ensuite poser des cartes sur le tas d'un premier. Les dessus ne sont plus rangés de gauche à droite, le fil de la plus longue suite croissante disparaît, et le nombre de tas, au moins \(\pi(n)\), n'a pas de formule connue : les tas des premiers servent d'accueil, si bien que les non-premiers ouvrent moins de tas qu'en jouant seuls. Pour 52 cartes distinctes, on obtient 22,2 tas en moyenne, contre 11,6 pour la patience ordinaire. Le cas extrême, pourtant, se compte exactement : le nombre de permutations de \(1,\ldots,n\) qui produisent \(n\) tas est le produit ci-dessus, c'est-à-dire \(a(n+1)\) pour la suite A080497. Ces permutations sont celles où les non-premiers sortent dans l'ordre croissant et où chaque premier \(p\) sort après tous les non-premiers plus petits que lui. Preuve : on écrit les non-premiers dans l'ordre, puis on glisse les premiers du plus grand au plus petit ; quand on glisse \(p\), les cartes déjà placées après le dernier non-premier plus petit que \(p\) sont exactement les \(n-p\) nombres plus grands que \(p\), d'où \(n+1-p\) places. Le choix du tas n'intervient pas : pour faire \(n\) tas, aucune carte ne se pose jamais sur un tas. Exemple : \(a(5)=6\), car pour \(n=4\) la carte 1 sort en premier, puis 2, 3 et 4 dans n'importe quel ordre. Règle scellée : personne ne peut recouvrir un premier. Les non-premiers jouent alors une patience ordinaire entre eux, et le nombre de tas vaut exactement \(\pi(n)\) plus la plus longue suite croissante des non-premiers, dans l'ordre du paquet. Le nombre de permutations à \(\pi(n)+k\) tas vaut donc \(\frac{n!}{m!}\,T(m,k)\), avec \(m=n-\pi(n)\) et \(T\) le triangle A047874. Le comptage arithmétique et la statistique des matrices aléatoires y sont séparés proprement.

sorte loifamille comptage ; nombres premiers
# la règle libre jusqu'à 8 cartes : les donnes à n tas contre A080497(n+1), puis le même compte en choisissant le tas au hasard ; la programmation dynamique jusqu'à n = 100 ; la ligne n = 8 du triangle ; la règle scellée contre la formule n!/m! × A047874 jusqu'à 8, puis sur 2 000 paquets de 100 cartes ; enfin les moyennes pour 52 cartes, règle libre puis scellée
from itertools import permutations
from math import factorial, prod
from functools import lru_cache
from collections import Counter
from sympy import isprime, primepi, primerange
import bisect, random
random.seed(1)
def tas(q, regle, choix=lambda ok: ok[0]):         # regle : 'libre' ou 'scellee'
    dessus = []
    for c in q:
        if isprime(c): dessus.append(None if regle == 'scellee' else c); continue
        ok = [i for i, t in enumerate(dessus) if t is not None and t > c]
        if ok: dessus[choix(ok)] = c
        else: dessus.append(c)
    return len(dessus)
def plsc(q):
    d = []
    for c in q:
        i = bisect.bisect_left(d, c)
        if i == len(d): d.append(c)
        else: d[i] = c
    return len(d)
A080497 = lambda N: prod(N - p for p in primerange(2, N))
libre = {n: Counter(tas(q, 'libre') for q in permutations(range(1, n + 1))) for n in range(1, 9)}
print([libre[n][n] for n in range(1, 9)], [A080497(n + 1) for n in range(1, 9)])# [1, 1, 2, 6, 12, 40, 90, 336] [1, 1, 2, 6, 12, 40, 90, 336]
print([sum(1 for q in permutations(range(1, n + 1)) if tas(q, 'libre', random.choice) == n) for n in range(1, 9)])# [1, 1, 2, 6, 12, 40, 90, 336]
def compte(n):                                   # programmation dynamique : non-premiers dans l'ordre, premiers insérés
    C = [c for c in range(1, n + 1) if not isprime(c)]; P = [p for p in range(1, n + 1) if isprime(p)]
    dispo = [sum(1 for p in P if j == len(C) or p < C[j]) for j in range(len(C) + 1)]
    @lru_cache(None)
    def f(j, t):
        if j == len(C) and t == len(P): return 1
        return (f(j + 1, t) if j < len(C) else 0) + ((dispo[j] - t) * f(j, t + 1) if t < dispo[j] else 0)
    return f(0, 0)
print(all(compte(n) == A080497(n + 1) for n in range(1, 101)), compte(30))# True 490311843840
print([libre[8][k] for k in range(1, 9)])# [0, 0, 0, 0, 14280, 20412, 5292, 336]
T = {m: Counter(plsc(q) for q in permutations(range(m))) if m else Counter({0: 1}) for m in range(0, 7)}
print(all(Counter(tas(q, 'scellee') for q in permutations(range(1, n + 1))) == Counter({int(primepi(n)) + k: factorial(n) // factorial(n - int(primepi(n))) * v for k, v in T[n - int(primepi(n))].items()}) for n in range(1, 9)))# True
print(all(tas(q, 'scellee') == primepi(len(q)) + plsc([c for c in q if not isprime(c)]) for q in (random.sample(range(1, 101), 100) for _ in range(2000))))# True
v = [tas(random.sample(range(1, 53), 52), 'libre') for _ in range(3000)]
w = [tas(random.sample(range(1, 53), 52), 'scellee') for _ in range(3000)]
print(round(sum(v)/len(v), 1), round(sum(w)/len(w), 1))# 22.2 24.5
L·114la patience, détecteur d'ordre
\(\text{tas}(x_1,\ldots,x_N)\)
=
\(\approx2\sqrt N\ \text{si les }x_k\text{ sont au hasard}\)

et sensiblement moins si la suite cache de l'ordre. On classe les valeurs d'une suite et l'on joue la patience sur leurs rangs (L·108) : pour 10 000 nombres tirés au hasard, on obtient 192,6 tas en moyenne, avec un écart type de 4. Les parties fractionnaires de \(k\sqrt2\), \(k\leq10\,000\), n'en donnent que 120 : c'est une rotation, très ordonnée. Celles de \(p\sqrt2\) pour les 10 000 premiers nombres premiers en donnent 138, à 13 écarts types sous le hasard, alors qu'elles sont parfaitement équiréparties (Vinogradov) : la patience voit l'ordre que deux premiers voisins héritent de la rotation, là où un test de répartition ne voit rien. C'est l'esprit de la conjecture de Sarnak : la fonction de Möbius ne devrait être corrélée à aucune suite déterministe simple. Sur la marche de Mertens \(M(n)=\mu(1)+\cdots+\mu(n)\), comparée à des marches qui gardent les zéros de \(\mu\) mais tirent les signes au hasard, la patience fait un peu moins de tas, toujours dans la fourchette normale. L'explication est l'amplitude : une suite strictement croissante d'entiers ne peut compter plus de valeurs que l'étendue de la marche, et une fois rapportés à cette étendue, les tas de Mertens sont tout à fait ordinaires. La vraie particularité est l'amplitude elle-même : jusqu'à \(10^{5}\), \(\max|M|/\sqrt N\) vaut 0,42, contre 0,98 ± 0,36 pour les marches au hasard (code ci-dessous) ; jusqu'à \(10^{6}\), 0,37 contre 0,94 ± 0,45, et la marche de Mertens est plus serrée que chacune des 60 marches au hasard essayées. C'est le confinement célèbre qui avait fait croire à la conjecture de Mertens, \(|M(x)|<\sqrt x\) pour tout \(x\), réfutée par Odlyzko et te Riele (1985) sans contre-exemple explicite : les dépassements arrivent à des hauteurs astronomiques. La marche n'est pas aléatoire, c'est une somme d'ondes en \(\ln x\), une par zéro de \(\zeta\) (L·70, L·107). Sous l'hypothèse de Riemann et une conjecture de Gonek et Hejhal, Ng a montré que \(M(x)/\sqrt x\), vue en échelle logarithmique, a une loi limite, et un argument probabiliste suggère des excursions de l'ordre de \(\sqrt x\,(\ln\ln\ln x)^{5/4}\). Rien de tout cela ne démontre l'hypothèse de Riemann (C·2) : ces mesures finies sont compatibles avec elle, comme elles l'étaient avec la conjecture de Mertens, qui est fausse.

sorte loifamille nombres premiers ; marches aléatoires
# 10 000 nombres au hasard (moyenne et écart type des tas), puis {k√2} et {p√2} ; la marche de Mertens jusqu'à 10⁵ : tas, étendue, tas rapportés à l'étendue, max|M|/√N ; les mêmes mesures sur 100 marches qui gardent les zéros de μ avec des signes au hasard ; les écarts en écarts types, et combien de marches au hasard sont plus serrées que Mertens
import bisect, math, random
import numpy as np
from sympy import primerange
from mpmath import mp, sqrt, frac
mp.dps = 40
def tas(v, strict=True):
    d, f = [], (bisect.bisect_left if strict else bisect.bisect_right)
    for c in v:
        i = f(d, c)
        if i == len(d): d.append(c)
        else: d[i] = c
    return len(d)
random.seed(1)
N = 10000
alea = [tas([random.random() for _ in range(N)]) for _ in range(100)]
m = sum(alea) / len(alea); s = math.sqrt(sum((x - m)**2 for x in alea) / len(alea))
P = list(primerange(2, 110000))[:N]
print(round(m, 1), round(s, 1), tas([float(frac(k * sqrt(2))) for k in range(1, N + 1)]), tas([float(frac(p * sqrt(2))) for p in P]))# 192.7 4.2 120 138
def mobius(n):
    mu = np.ones(n + 1, dtype=np.int64); mu[0] = 0; premier = np.ones(n + 1, bool); premier[:2] = False
    for p in range(2, n + 1):
        if premier[p]: premier[p*p::p] = False; mu[p::p] *= -1; mu[p*p::p*p] = 0
    return mu
N = 10**5
mu = mobius(N)[1:]
rng = np.random.default_rng(7)
def mesures(pas):
    w = np.cumsum(pas); etendue = int(w.max() - w.min()) + 1
    return tas(w.tolist()), etendue, tas(w.tolist()) / etendue, float(np.abs(w).max() / math.sqrt(N))
M = mesures(mu)
H = np.array([mesures(np.where(mu != 0, rng.choice([-1, 1], N), 0)) for _ in range(100)])
print(M[0], M[1], round(M[2], 3), round(M[3], 3))# 209 229 0.913 0.417
print([f'{H[:, k].mean():.2f} ± {H[:, k].std():.2f}' for k in range(4)])# ['320.12 ± 123.33', '390.23 ± 111.88', '0.84 ± 0.22', '0.98 ± 0.36']
print([round(float((M[k] - H[:, k].mean()) / H[:, k].std()), 2) for k in range(4)], int(np.sum(H[:, 3] < M[3])))# [-0.9, -1.44, 0.34, -1.56] 2
L·115le voyageur sur la grille
\(\text{aire}(\gamma)\)
=
\(\tfrac{N}{2}-1\)

pour toute tournée \(\gamma\) qui passe une fois et une seule par chacun des \(N\) points d'une grille rectangulaire \(m\times n\), en ne suivant que les arêtes de la grille : un cycle hamiltonien. Sur la grille, le problème du voyageur de commerce n'a plus d'enjeu, toutes les tournées ont la même longueur \(N\) ; reste la vraie question, combien y en a-t-il ? Aucune si \(m\) et \(n\) sont impairs : colorions les points en damier, la tournée alterne les couleurs, il faut donc autant de points de chaque couleur, et \(N\) doit être pair. Pour un rectangle, c'est la seule obstruction ; sur une grille trouée, décider s'il existe une tournée devient NP-complet (Itai, Papadimitriou et Szwarcfiter, 1982). L'aire vient de la formule de Pick (L·54) : tous les points sont sur la tournée, aucun dedans, donc \(\mathcal A=0+\tfrac N2-1\). Autrement dit, la tournée enferme exactement \(\tfrac N2-1\) carrés unités, et leurs centres, les coins des cases, forment un arbre : tous reliés, sans cycle. Réciproquement, un ensemble de coins est l'intérieur d'une tournée si et seulement si c'est un arbre qui touche chaque point de la grille, et qui ne se pince nulle part en diagonale. Cette dernière condition est le piège : deux coins qui ne se touchent que par la pointe forcent la tournée à repasser par le même point. Sur la grille 4 × 6, l'oublier donne 39 arbres au lieu de 37 tournées. Compter les tournées, c'est compter ces arbres, et il n'existe pas de formule : on lit la grille colonne par colonne en notant quels coins sont dedans et lesquels sont déjà reliés par la gauche. Par exemple, la tournée 4 × 6 dont les coins intérieurs sont, ligne par ligne, 11111 / 10010 / 10111, se lit 0, (1), (1), (1, 2), (1), (1, 1), 0 : la quatrième colonne a deux blocs pas encore reliés, qui se rejoignent ensuite. C'est le codage de Stoyan et Strehl (1995). Sans les étiquettes, un tableau dont chaque paire de colonnes voisines existe dans une vraie tournée peut encore être faux : 0, (1), (1), (1, 2), 0 laisse le bloc 2 disparaître sans s'être raccroché, et n'a d'ailleurs que 6 coins sur la grille 4 × 4, au lieu des 7 qu'exige l'aire. Les grilles carrées \(2n\times2n\) donnent 1, 6, 1 072, 4 638 576, 467 260 456 608, 1 076 226 888 605 605 706 (A003763) ; les grilles \(n\times(n+1)\), 1, 2, 14, 154, 5 320, 301 384… (A222200) ; le tableau complet est A321172. Chaque point multiplie le nombre de tournées par environ 1,4728, constante estimée numériquement (Jacobsen et Kondev, 1998) et dont on ne connaît aucune forme close, alors que celle des dominos en a une (L·117). Bandes de hauteur fixe : L·116 ; la même question sur une roue : L·118.

sorte loifamille comptage ; géométrie
# force brute sur six grilles ; matrice de transfert, force brute et arbres de coins concordent ; les arbres sans puis avec la condition de pincement sur 4 × 6 ; l'aire de chaque tournée trouvée ; les grilles impaires ; les grilles carrées 2n × 2n, puis n × (n+1) ; le codage par colonnes d'une vraie tournée 4 × 6 et d'un faux tableau 4 × 4 (étiquettes, nombre de coins)
from collections import defaultdict
def norm(t):
    mp = {}
    return tuple(0 if x == 0 else mp.setdefault(x, len(mp) + 1) for x in t)
def H(m, n):                                   # matrice de transfert, case par case, prises étiquetées par composante
    if n > m: m, n = n, m
    st = {(0,) * (n + 1): 1}; tot = 0
    for r in range(m):
        for c in range(n):
            nx = defaultdict(int)
            for s, v in st.items():
                if c == 0 and s[n]: continue
                up, left = s[c], (s[n] if c else 0)
                b = list(s); b[c] = b[n] = 0
                if up and left:
                    if up != left: nx[norm([up if x == left else x for x in b])] += v
                    elif r == m - 1 and c == n - 1 and not any(b): tot += v
                elif up or left:
                    for d, rt, ok in ((up or left, 0, r < m - 1), (0, up or left, c < n - 1)):
                        if ok: t = b[:]; t[c], t[n] = d, rt; nx[norm(t)] += v
                elif r < m - 1 and c < n - 1:
                    t = b[:]; t[c] = t[n] = n + 1; nx[norm(t)] += v
            st = nx
    return tot
def cycles(m, n):                              # force brute : chaque cycle une fois (on fixe le sens)
    N, out, ch, vu = m * n, [], [(0, 0)], {(0, 0)}
    vois = lambda p: [(p[0] + a, p[1] + b) for a, b in ((1, 0), (0, 1), (-1, 0), (0, -1)) if 0 <= p[0] + a < m and 0 <= p[1] + b < n]
    def dfs():
        p = ch[-1]
        if len(ch) == N:
            if (0, 0) in vois(p) and ch[1] < p: out.append(ch[:])
            return
        for q in vois(p):
            if q not in vu: vu.add(q); ch.append(q); dfs(); ch.pop(); vu.discard(q)
    dfs(); return out
aire = lambda c: abs(sum(c[i][0] * c[i - 1][1] - c[i - 1][0] * c[i][1] for i in range(len(c)))) / 2
def arbres(m, n, pince=True):                              # coins intérieurs : un arbre qui touche chaque point, sans pincement en diagonale
    P = [(i, j) for i in range(m - 1) for j in range(n - 1)]; k = 0
    for masque in range(1, 1 << len(P)):
        S = {P[t] for t in range(len(P)) if masque >> t & 1}
        motifs = [tuple((a, b) in S for a in (r - 1, r) for b in (c - 1, c)) for r in range(m) for c in range(n)]
        if any(not any(x) or pince and x in ((True, False, False, True), (False, True, True, False)) for x in motifs): continue
        if sum((a + 1, b) in S for a, b in S) + sum((a, b + 1) in S for a, b in S) != len(S) - 1: continue
        pile, vus = [min(S)], {min(S)}
        while pile:
            a, b = pile.pop()
            for q in ((a + 1, b), (a - 1, b), (a, b + 1), (a, b - 1)):
                if q in S and q not in vus: vus.add(q); pile.append(q)
        k += len(vus) == len(S)
    return k
def etiquettes(T):                             # codage de Stoyan et Strehl, colonne par colonne
    S = {(i, j) for i, l in enumerate(T) for j, x in enumerate(l) if x == '1'}; pere, out = {}, []
    f = lambda x: x if pere[x] == x else f(pere[x])
    for j in range(len(T[0])):
        for i in range(len(T)):
            if (i, j) in S:
                pere.setdefault((i, j), (i, j))
                for q in ((i - 1, j), (i, j - 1)):
                    if q in S: pere[f((i, j))] = f(q)
        mp = {}
        out.append(tuple(mp.setdefault(f((i, j)), len(mp) + 1) for i in range(len(T)) if (i, j) in S and (i - 1, j) not in S) or 0)
    return out, len(S)
G = [(2, 2), (3, 4), (4, 4), (4, 5), (4, 6), (3, 6)]
print([len(cycles(m, n)) for m, n in G])# [1, 2, 6, 14, 37, 4]
print([H(m, n) for m, n in G] == [len(cycles(m, n)) for m, n in G] == [arbres(m, n) for m, n in G])# True
print(arbres(4, 6, pince=False), arbres(4, 6))# 39 37
print(all(aire(c) == m * n / 2 - 1 for m, n in G for c in cycles(m, n)))# True
print([H(m, n) for m, n in ((3, 3), (3, 5), (5, 5), (5, 7), (7, 7))])# [0, 0, 0, 0, 0]
print([H(2 * k, 2 * k) for k in range(1, 7)])# [1, 6, 1072, 4638576, 467260456608, 1076226888605605706]
print([H(n, n + 1) for n in range(2, 9)])# [1, 2, 14, 154, 5320, 301384, 49483138]
print(etiquettes(["0000000", "0111110", "0100100", "0101110", "0000000"]))# ([0, (1,), (1,), (1, 2), (1,), (1, 1), 0], 11)
print(etiquettes(["00000", "01110", "01000", "01010", "00000"]))# ([0, (1,), (1,), (1, 2), 0], 6)
L·116la bande de hauteur 4
\(H_{4\times n}\)
=
\(2H_{4\times(n-1)}+2H_{4\times(n-2)}-2H_{4\times(n-3)}+H_{4\times(n-4)}\)

pour \(n\geq5\), où \(H_{4\times n}\) compte les tournées hamiltoniennes de la grille de \(4\times n\) points (L·115) : 0, 1, 2, 6, 14, 37, 92, 236, 596, 1 517, 3 846… (A006864), de série génératrice \(\dfrac{x^2}{1-2x-2x^2+2x^3-x^4}\). La raison est générale : pour une hauteur fixée, une colonne ne peut se trouver que dans un nombre fini d'états (quels coins sont dedans, lesquels sont déjà reliés), et la tournée se lit comme un mot reconnu par un automate fini. Une série produite par un automate fini est toujours une fraction rationnelle, donc ses coefficients suivent une récurrence linéaire. Les récurrences les plus courtes ont pour ordres 2, 4, 6, 14 et 36 pour les hauteurs 3 à 7 : en hauteur 3, \(H_{3\times n}=2H_{3\times(n-2)}\) (des puissances de 2) ; en hauteur 5, \(H_{5\times n}=11H_{5\times(n-2)}+2H_{5\times(n-6)}\), qui ne voit que les \(n\) pairs (A006865). L'automate grossit vite avec la hauteur, d'où l'absence de formule pour la grille entière. La croissance vient de la plus grande racine du dénominateur : \(H_{4\times n}\) est multiplié par \(\lambda\approx2{,}538616\) à chaque colonne, soit 1,2623 par point. Ce taux par point vaut 1,26, 1,27, 1,33 et 1,33 pour les hauteurs 4 à 7, et monte lentement vers la constante 1,4728 de la grille entière. La roue lcm, par contraste : la roue lcm de nimbers se lit elle aussi colonne par colonne, rayon après rayon, mais son automate n'a qu'un cycle de \(L\) états, sans aucun choix. Sa série a pour dénominateur \(1-z^L=\prod_{d\mid L}\Phi_d(z)\), dont toutes les racines sont sur le cercle unité : périodique, d'entropie nulle. Celui des tournées bifurque, et une racine de son dénominateur, \(1/\lambda\), passe à l'intérieur du cercle. Déroulée, la roue ne dessine d'ailleurs jamais de tournée : deux entiers consécutifs sont premiers entre eux, donc deux 1 ne sont jamais côte à côte, et ses coins forment une poussière, pas un arbre. Seul le rayon plein, isolé, code une tournée : l'épingle à cheveux de la bande de largeur 2.

sorte loifamille comptage
# la bande de hauteur 4 jusqu'à n = 60 : premiers termes, la récurrence et celle que retrouve Berlekamp–Massey, la série génératrice ; la racine dominante, le dernier rapport, le taux par point ; les ordres des récurrences pour les hauteurs 3 à 7 (sur 100 termes), celles des hauteurs 3 et 5 ; le taux par point pour les hauteurs 4 à 7
from collections import defaultdict
from fractions import Fraction as Fr
import numpy as np
def norm(t):
    mp = {}
    return tuple(0 if x == 0 else mp.setdefault(x, len(mp) + 1) for x in t)
def H(m, n):                                   # la matrice de transfert de L·115
    if n > m: m, n = n, m
    st = {(0,) * (n + 1): 1}; tot = 0
    for r in range(m):
        for c in range(n):
            nx = defaultdict(int)
            for s, v in st.items():
                if c == 0 and s[n]: continue
                up, left = s[c], (s[n] if c else 0)
                b = list(s); b[c] = b[n] = 0
                if up and left:
                    if up != left: nx[norm([up if x == left else x for x in b])] += v
                    elif r == m - 1 and c == n - 1 and not any(b): tot += v
                elif up or left:
                    for d, rt, ok in ((up or left, 0, r < m - 1), (0, up or left, c < n - 1)):
                        if ok: t = b[:]; t[c], t[n] = d, rt; nx[norm(t)] += v
                elif r < m - 1 and c < n - 1:
                    t = b[:]; t[c] = t[n] = n + 1; nx[norm(t)] += v
            st = nx
    return tot
def bm(s):                                     # Berlekamp–Massey : la plus courte récurrence linéaire
    C, B, L, m, b = [Fr(1)], [Fr(1)], 0, 1, Fr(1)
    for n in range(len(s)):
        d = s[n] + sum(C[i] * s[n - i] for i in range(1, L + 1))
        if d == 0: m += 1; continue
        T = C[:]; coef = d / b
        C = C + [Fr(0)] * (len(B) + m - len(C))
        for i, x in enumerate(B): C[i + m] -= coef * x
        if 2 * L <= n: L, B, b, m = n + 1 - L, T, d, 1
        else: m += 1
    return [int(-x) for x in C[1:L + 1]]
a = [H(4, n) for n in range(1, 61)]
print(a[:12])                 # [0, 1, 2, 6, 14, 37, 92, 236, 596, 1517, 3846, 9770]
print(all(a[n] == 2 * a[n - 1] + 2 * a[n - 2] - 2 * a[n - 3] + a[n - 4] for n in range(4, 60)), bm(a))# True [2, 2, -2, 1]
serie = []                                     # coefficients de x²/(1 − 2x − 2x² + 2x³ − x⁴)
for k in range(60): serie.append((k == 2) + sum(w * serie[k - i] for i, w in ((1, 2), (2, 2), (3, -2), (4, 1)) if k >= i))
print(serie[1:] == a[:59])    # True
lam = max(abs(np.roots([1, -2, -2, 2, -1])))
print(round(float(lam), 6), round(a[-1] / a[-2], 6), round(float(lam) ** 0.25, 4))# 2.538616 2.538616 1.2623
rec = {h: bm([H(h, n) for n in range(1, 101)]) for h in range(3, 8)}
print({h: len(r) for h, r in rec.items()}, rec[3], rec[5])# {3: 2, 4: 4, 5: 6, 6: 14, 7: 36} [0, 2] [0, 11, 0, 0, 0, 2]
print([round(float(max(abs(np.roots([1] + [-x for x in rec[h]])))) ** (1 / h), 4) for h in range(4, 8)])# [1.2623, 1.2712, 1.3347, 1.3342]
L·117les dominos de Kasteleyn
\(D_{m\times n}\)
=
\(\prod_{j=1}^{\lceil m/2\rceil}\prod_{k=1}^{\lceil n/2\rceil}\Bigl(4\cos^2\tfrac{j\pi}{m+1}+4\cos^2\tfrac{k\pi}{n+1}\Bigr)\)

pour le nombre de façons de paver un rectangle de \(m\times n\) cases par des dominos \(1\times2\) (Kasteleyn ; Temperley et Fisher, 1961). Le produit de cosinus, irrationnel terme à terme, tombe toujours sur un entier. L'échiquier se pave de 12 988 816 façons, soit \(2^4\times901^2\) ; les carrés \(2n\times2n\) donnent 1, 2, 36, 6 728, 12 988 816, 258 584 046 368… (A004003, de la forme \(2^n\) fois un carré), le tableau complet est A099390. La bande \(2\times n\) donne les nombres de Fibonacci, la bande \(3\times2n\) 3, 11, 41, 153… Un rectangle aux deux côtés impairs ne se pave pas, et le facteur \(j=\tfrac{m+1}2,\ k=\tfrac{n+1}2\) du produit est nul. Pourquoi une formule produit ici, et pas pour les tournées (L·115) : Kasteleyn montre que le nombre de pavages est la racine carrée d'un déterminant, celui d'une matrice d'adjacence aux signes bien choisis. Ce déterminant se diagonalise comme les modes d'une membrane vibrante, et les cosinus en sont les fréquences propres. Les tournées n'ont pas cette structure : compter les cycles hamiltoniens d'un graphe quelconque est #P-complet (Valiant, 1979), et même sur la grille carrée, leur constante de croissance n'est connue que numériquement. Pour les dominos, au contraire, chaque case apporte un facteur exact \(e^{G/\pi}\approx1{,}3385\), où \(G\) est la constante de Catalan (III·1) : \(\ln D_{n\times n}/n^2\to G/\pi\). Une erreur fréquente : on lit parfois que Kasteleyn aurait résolu le modèle d'Ising. Ce modèle d'aimant a été résolu en dimension 2 par Onsager, en 1944 ; la méthode de Kasteleyn le retrouve en 1963, en le ramenant à des dominos sur un graphe décoré.

sorte loifamille comptage ; constante de Catalan
# comptage exact par profils contre la formule de Kasteleyn pour tous les rectangles jusqu'à 9 × 9 ; les carrés 2n × 2n ; l'échiquier ; la bande 2 × n ; la bande 3 × 2n ; ln D/n² pour n = 400 contre G/π ; e^(G/π)
from collections import defaultdict
from mpmath import mp, cos, pi, nint, log, catalan, fprod, fsum
mp.dps = 60
def D(m, n):                                   # force exacte : profil de bits, rangée par rangée
    f = {0: 1}
    for _ in range(m):
        g = defaultdict(int)
        for masque, v in f.items():
            def remplir(c, suivant):
                if c == n: g[suivant] += v; return
                if masque >> c & 1: remplir(c + 1, suivant); return
                remplir(c + 1, suivant | 1 << c)
                if c + 1 < n and not masque >> (c + 1) & 1: remplir(c + 2, suivant)
            remplir(0, 0)
        f = g
    return f.get(0, 0)
K = lambda m, n: int(nint(fprod(4 * cos(j * pi / (m + 1))**2 + 4 * cos(k * pi / (n + 1))**2
                                for j in range(1, (m + 1) // 2 + 1) for k in range(1, (n + 1) // 2 + 1))))
print(all(D(m, n) == K(m, n) for m in range(1, 10) for n in range(1, 10)))# True
print([K(2 * k, 2 * k) for k in range(0, 7)])# [1, 2, 36, 6728, 12988816, 258584046368, 53060477521960000]
print(K(8, 8), K(8, 8) == 2**4 * 901**2)# 12988816 True
print([K(2, n) for n in range(1, 13)])# [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
print([D(3, 2 * k) for k in range(1, 9)])# [3, 11, 41, 153, 571, 2131, 7953, 29681]
n = 400
print(float(fsum(log(4 * cos(j * pi / (n + 1))**2 + 4 * cos(k * pi / (n + 1))**2) for j in range(1, n // 2 + 1) for k in range(1, n // 2 + 1)) / n**2), float(catalan / pi))# 0.29081592043134397 0.2915609040308188
print(float(mp.e**(catalan / pi)))# 1.3385151519760967
L·118les boucles de la roue
\(\#\{\text{boucles qui font le tour}\}\)
=
\(2^L-2\)

sur la roue de trois anneaux de \(L\) points reliés par ses \(L\) rayons (le graphe \(P_3\times C_L\)), en comptant les boucles qui passent une fois et une seule par chacun des \(3L\) points (L·115) et font le tour du centre. Un ruban, une boucle : entre deux rayons voisins, une telle boucle traverse le secteur soit par un seul brin, sur l'anneau intérieur ou extérieur, soit par trois brins en S, et les brins simples alternent forcément, intérieur, extérieur, intérieur… Posons un bit sur chaque rayon : deux bits égaux encadrent un S, un passage de 0 à 1 dans le sens des aiguilles d'une montre est un brin intérieur, de 1 à 0 un brin extérieur. Les changements de bit alternent d'eux-mêmes, et chaque ruban binaire donne une boucle, sauf les deux rubans constants, qui ne font que des S : chaque anneau s'y referme sur lui-même, trois cercles et pas une boucle. Fermat sur la roue : tourner d'un cran fait tourner le ruban ; si \(L\) est premier, aucune boucle ne revient sur elle-même avant un tour complet, les boucles vont par paquets de \(L\), et \(L\) divise \(2^L-2\) (L·40). À rotation près, le lemme de Burnside donne \(\frac1L\sum_{d\mid L}\varphi(d)\,2^{L/d}-2\), les colliers binaires (A000031) moins les deux colliers unis ; les boucles de période exacte \(L\), celles qui ne viennent d'aucune roue plus petite, sont \(\sum_{d\mid L}\mu(L/d)\,2^d\) (A027375). L'argument vaut pour tout nombre \(r\geq2\) d'anneaux : une boucle invariante par un cran utiliserait des anneaux entiers, donc pour \(L\) premier le nombre total de boucles est toujours un multiple de \(L\). Les autres boucles : quand \(L\) est pair, des boucles enferment un morceau de couronne sans le centre ; avec trois anneaux, il y en a \(L\cdot2^{L/2-1}\), vérifié jusqu'à 10 sans démonstration ici. Le total, 6, 22, 30, 86, 126, 318, 510, 1 182, est la ligne des trois anneaux de la table A359855. Parité : une boucle qui ne fait pas le tour a une longueur paire, une boucle qui fait le tour une fois a la parité de \(L\) ; avec \(r\) anneaux elle a \(rL\) arêtes, donc si \(r\) et \(L\) sont impairs toutes les boucles font le tour, et si \(r\) est pair et \(L\) impair, aucune. Plus d'anneaux : le ruban ne suffit plus. Avec cinq anneaux, un secteur peut prendre jusqu'à seize formes (un, trois ou cinq brins sur divers anneaux), et respecter les règles d'un secteur au suivant ne garantit plus une seule boucle : pour six rayons, 4 178 des 33 964 mots valides localement donnent une seule boucle qui fait le tour, soit 12 %, les autres se cassent en plusieurs boucles. Les boucles qui font le tour valent 24, 170, 850, 4 178 pour trois à six rayons, sans formule connue. La raison : avec trois anneaux, la mémoire d'un secteur au suivant tient en un bit ; au-delà, il faut retenir quels brins sont déjà reliés, comme dans le codage de Stoyan et Strehl (L·115). Fermat et la loi de parité, eux, restent vrais. À l'infini : trois anneaux gardent exactement un bit par rayon, soit \(2^{1/3}\approx1{,}26\) par point. Avec plus d'anneaux, un bit par rayon ne suffit plus, et la croissance par point monte vers la constante 1,4728 de la grille infinie (L·115, L·116). Le ruban d'un anneau de la roue lcm, un 1 sur chaque multiple de \(k\), est lui-même une boucle. Avec les diagonales : L·119. Atelier interactif : les boucles de la roue.

sorte loifamille comptage ; nombres premiers
# force brute avec trois anneaux pour L = 3 à 10 : les boucles qui font le tour, contre 2^L − 2 ; les rubans redonnent exactement ces boucles ; les boucles qui ne font pas le tour contre L·2^(L/2−1) ; le total ; les orbites par rotation contre les colliers moins 2, celles de taille L contre la somme de Möbius ; L premier divise le nombre total de boucles avec 2, 4 et 5 anneaux ; la loi de parité (font-elles le tour ?) avec 4, 5 et 3 anneaux ; avec cinq anneaux, par mots de secteurs : les boucles qui font le tour, toutes les boucles (la ligne 5 de A359855), le nombre de formes de secteur, les boucles et les mots valides localement pour six rayons, Fermat pour 3 et 5 rayons
import sys
from sympy import totient, divisors, mobius
sys.setrecursionlimit(10000)
def cycles(r, L):                              # force brute : r anneaux de L points, reliés par les rayons
    adj = {(a, s): [(a, (s + 1) % L), (a, (s - 1) % L)] + [(b, s) for b in (a - 1, a + 1) if 0 <= b < r] for a in range(r) for s in range(L)}
    N, out, ch, vu = r * L, [], [(0, 0)], {(0, 0)}
    def dfs():
        p = ch[-1]
        if len(ch) == N:
            if (0, 0) in adj[p] and ch[1] < p: out.append(ch[:])
            return
        for q in adj[p]:
            if q not in vu: vu.add(q); ch.append(q); dfs(); ch.pop(); vu.discard(q)
    dfs(); return out
def tours(c, L):                               # nombre de tours autour du centre
    return sum(((b[1] - a[1]) % L == 1) - ((b[1] - a[1]) % L == L - 1) for a, b in zip(c, c[1:] + c[:1])) // L
aretes = lambda c: frozenset(frozenset(e) for e in zip(c, c[1:] + c[:1]))
def ruban(w):                                  # la boucle d'un ruban : S, brin intérieur ou extérieur par secteur
    L = len(w); typ = lambda s: 'S' if w[s] == w[(s + 1) % L] else ('I' if w[s] == 0 else 'O')
    E = {frozenset(((a, s), (a, (s + 1) % L))) for s in range(L) for a in {'S': (0, 1, 2), 'I': (0,), 'O': (2,)}[typ(s)]}
    for s in range(L):
        g, d = typ((s - 1) % L), typ(s)
        if (g != 'O') + (d != 'O') < 2: E.add(frozenset(((0, s), (1, s))))
        if (g != 'I') + (d != 'I') < 2: E.add(frozenset(((1, s), (2, s))))
    return frozenset(E)
tourne = lambda E, k, L: frozenset(frozenset((a, (s + k) % L) for a, s in e) for e in E)
def orbite(E, L): return len({tourne(E, k, L) for k in range(L)})
B = {L: cycles(3, L) for L in range(3, 11)}
T = {L: [aretes(c) for c in B[L] if tours(c, L)] for L in B}
print([len(T[L]) for L in B]) # [6, 14, 30, 62, 126, 254, 510, 1022]
print(all(len(T[L]) == 2**L - 2 for L in B))# True
print(all({ruban([m >> i & 1 for i in range(L)]) for m in range(1, 2**L - 1)} == set(T[L]) for L in B))# True
print([len(B[L]) - len(T[L]) for L in range(4, 11, 2)], [L * 2**(L // 2 - 1) for L in range(4, 11, 2)])# [8, 24, 64, 160] [8, 24, 64, 160]
print([len(B[L]) for L in B]) # [6, 22, 30, 86, 126, 318, 510, 1182]
print([len({frozenset(tourne(E, k, L) for k in range(L)) for E in T[L]}) for L in B] == [sum(totient(d) * 2**(L // d) for d in divisors(L)) // L - 2 for L in B])# True
print([sum(orbite(E, L) == L for E in T[L]) for L in B] == [sum(mobius(L // d) * 2**d for d in divisors(L)) for L in B])# True
print([len(cycles(r, L)) % L for r, L in ((2, 5), (2, 7), (4, 5), (4, 7), (5, 3), (5, 5))])# [0, 0, 0, 0, 0, 0]
print([{tours(c, L) != 0 for c in cycles(r, L)} for r, L in ((4, 3), (4, 5), (4, 7), (5, 3), (5, 5), (3, 9))])# [{False}, {False}, {False}, {True}, {True}, {True}]
import itertools
from collections import Counter
def rayons(r, A, B):                           # rayons imposés par les arcs des deux secteurs voisins (degré 2 partout)
    x, avant = [], 0
    for a in range(r):
        besoin = 2 - (a in A) - (a in B) - avant
        if besoin not in (0, 1) or (a == r - 1 and besoin): return None
        if a < r - 1: x.append(besoin); avant = besoin
    return tuple(x)
def mots(r, L):                                # mots de secteurs localement valides, et nombre de boucles qu'ils dessinent
    lettres = [frozenset(c) for k in range(r + 1) for c in itertools.combinations(range(r), k)]
    ok = {(A, B): x for A in lettres for B in lettres if (x := rayons(r, A, B)) is not None}
    suite = {A: [B for B in lettres if (A, B) in ok] for A in lettres}
    res = Counter(); formes = set()
    def boucles(m):
        pere = {}
        def f(x):
            while pere.setdefault(x, x) != x: x = pere[x]
            return x
        for s in range(L):
            for a in m[s]: pere[f((a, s))] = f((a, (s + 1) % L))
            for a, v in enumerate(ok[(m[s - 1], m[s])]):
                if v: pere[f((a, s))] = f((a + 1, s))
        return len({f((a, s)) for a in range(r) for s in range(L)})
    def dfs(m):
        if len(m) == L:
            if (m[-1], m[0]) in ok:
                k = boucles(m); res[(len(m[0]) % 2, k == 1)] += 1
                if k == 1 and len(m[0]) % 2: formes.update(m)
            return
        for B in suite[m[-1]]: dfs(m + [B])
    for A in lettres: dfs([A])
    return res, len(formes)
R5 = {L: mots(5, L) for L in range(3, 7)}
print([R5[L][0][(1, True)] for L in R5])# [24, 170, 850, 4178]
print([R5[L][0][(1, True)] + R5[L][0][(0, True)] for L in R5])# [24, 306, 850, 7010]
print(R5[6][1], R5[6][0][(1, True)], R5[6][0][(1, True)] + R5[6][0][(1, False)])# 16 4178 33964
print([R5[L][0][(1, True)] % L for L in (3, 5)])# [0, 0]
L·119les diagonales de la roue
\(\#\{\text{boucles}\}\)
=
\(2^{L-1}\bigl(2\,\mathrm{Lucas}(L)+2L+1\bigr)\)

sur la roue à deux anneaux de \(L\) points (L·118) où l'on autorise aussi les diagonales de chaque case : chaque point est relié à ses deux voisins d'anneau et aux trois points voisins de l'autre anneau, comme le roi aux échecs, et l'on compte les boucles qui passent une fois et une seule par chacun des \(2L\) points. \(\mathrm{Lucas}(L)=\varphi^L+(-1/\varphi)^L\) est le nombre de Lucas (A000032), si bien que \(2^L\mathrm{Lucas}(L)=(1+\sqrt5)^L+(1-\sqrt5)^L\) : le nombre d'or gouverne la croissance. Pour \(L=3\), la roue est le graphe complet à six points, et l'on retrouve \(5!/2=60\). La loi de parité de L·118 disparaît, car les diagonales ferment des triangles. Sans croisement, si l'on interdit de prendre les deux diagonales d'une même case : les boucles qui font le tour valent \((1+\sqrt3)^L+(1-\sqrt3)^L\), soit 20, 56, 152, 416, 1 136… (A080040, \(a(n)=2a(n-1)+2a(n-2)\)), et celles qui restent sur place exactement \(3L\). Fermat déformé : pour \(L\) premier, le compte n'est plus un multiple de \(L\), mais vaut 2 de plus sans croisement, 3 de plus avec. C'est que certaines boucles ne bougent plus quand on tourne la roue : deux hélices en escalier en colimaçon (diagonale, rayon, diagonale, rayon…) et, quand \(L\) est impair, un zigzag qui prend les deux diagonales de chaque case. Les autres boucles vont par paquets de \(L\). On reconnaît le petit théorème de Fermat des traces, \(\mathrm{Tr}(M^p)\equiv\mathrm{Tr}(M)\pmod p\) : \(\mathrm{Lucas}(p)\equiv1\) et \((1+\sqrt3)^p+(1-\sqrt3)^p\equiv2\pmod p\). Formules trouvées sur \(L=3\) à 10 et confirmées sur \(L=11\) (431 104 boucles, 63 329 sans croisement) ; le code les vérifie jusqu'à 9. Trois anneaux avec diagonales : 648, 5 670, 42 000 boucles pour trois à cinq rayons, dont 270, 1 578, 8 650 sans croisement ; pas encore de formule. Atelier interactif : les boucles de la roue, mode « diagonales ».

sorte loifamille comptage ; nombre d'or
# force brute avec deux anneaux, L = 3 à 9 : toutes les boucles, contre la formule de Lucas ; les boucles sans croisement qui font le tour, contre (1 + √3)^L + (1 − √3)^L ; celles qui restent sur place, contre 3L ; les restes modulo L premier (toutes, puis sans croisement) ; les boucles invariantes par un cran (sans croisement, toutes) ; Lucas(p) modulo p ; trois anneaux, L = 3 à 5 : toutes, sans croisement, sans croisement qui font le tour
import sys
from collections import Counter
from sympy import sqrt, expand, lucas, isprime
sys.setrecursionlimit(10000)
def boucles(r, L):                              # force brute, roue à r anneaux avec rayons et diagonales
    adj = {(a, s): list(dict.fromkeys([(a, (s + 1) % L), (a, (s - 1) % L)] + [(b, (s + k) % L) for b in (a - 1, a + 1) if 0 <= b < r for k in (0, 1, -1)])) for a in range(r) for s in range(L)}
    N, out, ch, vu = r * L, [], [(0, 0)], {(0, 0)}
    def dfs():
        p = ch[-1]
        if len(ch) == N:
            if (0, 0) in adj[p] and ch[1] < p: out.append(ch[:])
            return
        for q in adj[p]:
            if q not in vu: vu.add(q); ch.append(q); dfs(); ch.pop(); vu.discard(q)
    dfs(); return out
def tours(c, L): return sum(((b[1] - a[1]) % L == 1) - ((b[1] - a[1]) % L == L - 1) for a, b in zip(c, c[1:] + c[:1])) // L
def croise(c, L):                               # une case dont les deux diagonales sont prises
    cases = Counter((min(a[0], b[0]), a[1] if (b[1] - a[1]) % L == 1 else b[1]) for a, b in zip(c, c[1:] + c[:1]) if a[0] != b[0] and a[1] != b[1])
    return any(v == 2 for v in cases.values())
aretes = lambda c: frozenset(frozenset(e) for e in zip(c, c[1:] + c[:1]))
tourne = lambda E, L: frozenset(frozenset((a, (s + 1) % L) for a, s in e) for e in E)
B = {L: boucles(2, L) for L in range(3, 10)}
tot = [len(B[L]) for L in B]
sc = [sum(not croise(c, L) for c in B[L]) for L in B]
sct = [sum(not croise(c, L) and tours(c, L) != 0 for c in B[L]) for L in B]
print(tot)                    # [60, 184, 528, 1568, 4672, 14208, 43776]
print(tot == [2**(L - 1) * (2 * lucas(L) + 2 * L + 1) for L in B])# True
print(sct, sct == [expand((1 + sqrt(3))**L + (1 - sqrt(3))**L) for L in B])# [20, 56, 152, 416, 1136, 3104, 8480] True
print([a - b for a, b in zip(sc, sct)] == [3 * L for L in B])# True
print([(L, tot[L - 3] % L, sct[L - 3] % L) for L in B if isprime(L)])# [(3, 0, 2), (5, 3, 2), (7, 3, 2)]
print([(sum(aretes(c) == tourne(aretes(c), L) and not croise(c, L) for c in B[L]), sum(aretes(c) == tourne(aretes(c), L) for c in B[L])) for L in B])# [(2, 3), (2, 2), (2, 3), (2, 2), (2, 3), (2, 2), (2, 3)]
print([lucas(p) % p for p in (3, 5, 7, 11, 13, 101)])# [1, 1, 1, 1, 1, 1]
T = {L: boucles(3, L) for L in range(3, 6)}
print([(len(T[L]), sum(not croise(c, L) for c in T[L]), sum(not croise(c, L) and tours(c, L) != 0 for c in T[L])) for L in T])# [(648, 270, 126), (5670, 1578, 634), (42000, 8650, 2970)]
L·120le 37 des répunits
\(\dfrac{\overline{dd\cdots d}}{d+d+\cdots+d}\)
=
\(\dfrac{R_n}{n}\)

pour tout chiffre \(d\) de 1 à 9 et toute longueur \(n\), où \(R_n=11\ldots1\) est le répunit à \(n\) chiffres, le nombre qui s'écrit avec \(n\) chiffres 1. Le chiffre s'en va : \(\overline{dd\cdots d}=d\,R_n\), et la somme des chiffres vaut \(nd\). Pour \(n=3\), c'est le tour du 37 : \(\frac{111}{1+1+1}=\frac{222}{2+2+2}=\cdots=\frac{999}{9+9+9}=37\). Quand tombe-t-on juste ? Exactement quand \(n\) divise \(R_n\), c'est-à-dire \(10^n\equiv1\pmod{9n}\) : \(n=1,3,9,27,81,111,243,333,729,999,2\,187\ldots\) (A014950), 30 valeurs sous 200 000. Pour \(n=9\), on trouve \(111\,111\,111/9=12\,345\,679\), la suite de 1 à 9 sans le 8 ; pour \(n=27\), \(4\,115\,226\,337\,448\,559\,670\,781\,893\). La loi du 3 : \(R_n\) contient exactement autant de facteurs 3 que \(n\), ni plus ni moins. C'est le lemme de « montée de l'exposant » : \(10^n-1\) a \(2+v_3(n)\) facteurs 3, et le 9 du dénominateur en emporte deux. Toutes les puissances de 3 conviennent donc, à l'infini. Pour sortir des puissances de 3, il faut que chaque autre facteur premier \(p\) de \(n\) divise aussi \(R_n\) : 37 divise 111, d'où \(111=3\times37\), 333, 999, puis \(4\,107=3\times37^2\) ; plus loin, \(13\,203=3^4\times163\), car 163 divise \(R_{81}\). En toute base \(b\), il faut que \(n\) divise \((b^n-1)/(b-1)\), soit \(b^n\equiv1\pmod{(b-1)n}\). En base 2, seul \(n=1\) convient, car \(n>1\) ne divise jamais \(2^n-1\) ; en base 4 : 1, 3, 9, 21, 27, 63, 81… Longueurs premières : seul 3 convient. Pour tout premier \(p\neq3\), le petit théorème de Fermat donne \(10^p\equiv10\pmod p\), donc \(9R_p\equiv9\) et \(R_p\equiv1\pmod p\) : le 37 est l'unique quotient entier de longueur première, et pour \(p\geq5\) le reste de la division vaut exactement le chiffre, \(77\,777=35\times2\,222+7\). Après le 9 : on remplace le chiffre par un bloc \(B\) de \(k\) chiffres écrit trois fois. Le bloc s'en va encore, et \(\overline{BBB}/(B+B+B)=(10^{2k}+10^k+1)/3\) : 37, 3 367, 333 667, 33 336 667… ; ainsi \(121212/(12+12+12)=3\,367\). La somme des inverses des répunits est dans L·77, les sommes infinies pondérées dans L·121, et leur tableau d'ensemble dans L·122.

sorte loifamille arithmétique
# le tour du 37 pour les neuf chiffres ; la loi R_n/n pour n jusqu'à 59 ; les quotients pour n = 1, 3, 9, puis 27 ; les n qui divisent R_n sous 200 000 (par 10^n ≡ 1 mod 9n), contrôlés directement jusqu'à 3 000 ; la loi du 3 jusqu'à 3 000 ; les facteurs des termes suivants ; le critère en base b de 2 à 12 ; les n qui conviennent en bases 2, 4 et 7 ; R_p modulo p pour les premiers sous 10 000 ; le reste égal au chiffre, et l'exemple 77 777 ; la suite 37, 3 367, 333 667… ; la loi des blocs triplés pour tous les blocs sous 100 000
from sympy import multiplicity, factorint
R = lambda n, b=10: (b**n - 1) // (b - 1)                  # répunit : n chiffres 1 en base b
rep = lambda d, n: int(str(d) * n)                          # le nombre ddd…d (n fois le chiffre d)
print({d: rep(d, 3) // (3 * d) for d in range(1, 10)})# {1: 37, 2: 37, 3: 37, 4: 37, 5: 37, 6: 37, 7: 37, 8: 37, 9: 37}
print(all(rep(d, n) * n == R(n) * (n * d) for d in range(1, 10) for n in range(1, 60)))# True
print([R(n) // n for n in (1, 3, 9)])# [1, 37, 12345679]
print(R(27) // 27)            # 4115226337448559670781893
A = [n for n in range(1, 200000) if pow(10, n, 9 * n) == 1]  # n divise R(n)  <=>  10^n ≡ 1 mod 9n
print(A[:15], len(A))         # [1, 3, 9, 27, 81, 111, 243, 333, 729, 999, 2187, 2997, 4107, 6561, 8991] 30
print(all((R(n) % n == 0) == (n in A) for n in range(1, 3000)))# True
print(all(multiplicity(3, R(n)) == multiplicity(3, n) for n in range(1, 3000)))# True
print([factorint(n) for n in A[5:13]])# [{3: 1, 37: 1}, {3: 5}, {3: 2, 37: 1}, {3: 6}, {3: 3, 37: 1}, {3: 7}, {3: 4, 37: 1}, {3: 1, 37: 2}]
print(all((pow(b, n, (b - 1) * n) == 1 % ((b - 1) * n)) == (R(n, b) % n == 0) for b in range(2, 13) for n in range(1, 300)))# True
print([[n for n in range(1, 100) if R(n, b) % n == 0] for b in (2, 4, 7)])# [[1], [1, 3, 9, 21, 27, 63, 81], [1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 20, 24, 27, 32, 36, 40, 48, 54, 57, 60, 64, 72, 80, 81, 96]]
from sympy import primerange
print(all((pow(10, p, 9 * p) - 1) // 9 % p == (0 if p == 3 else 1) for p in primerange(2, 10**4)))# True
print(all(int(str(d) * p) % (p * d) == d for p in primerange(5, 200) for d in range(1, 10)), int('7' * 5) // 35, int('7' * 5) % 35)# True 2222 7
print([(10**(2 * k) + 10**k + 1) // 3 for k in range(1, 5)])# [37, 3367, 333667, 33336667]
print(all(int(str(B) * 3) == 3 * B * ((10**(2 * len(str(B))) + 10**len(str(B)) + 1) // 3) for B in range(1, 10**5)))# True
L·121les répunits pondérés
\(\sum_{n\geq1}\frac{n}{R_n}\)
=
\(9\sum_{k\geq1}\frac{\sigma(k)}{10^k}\)

où \(R_n=11\ldots1\) est le répunit à \(n\) chiffres et \(\sigma(k)\) la somme des diviseurs de \(k\). La valeur commune est \(1{,}212956684547005893103132\ldots\) C'est l'inverse des quotients de L·120 qui converge : chaque \(\overline{dd\cdots d}/(d+\cdots+d)=R_n/n\) grandit sans fin, mais \(n/R_n=9n/(10^n-1)\) est une série de Lambert, \(\sum_n n\,x^n/(1-x^n)=\sum_k\sigma(k)\,x^k\) en \(x=1/10\). On lit donc les sommes de diviseurs 1, 3, 4, 7, 6, 12, 8, 15… comme des « décimales » qui se chevauchent. Un triptyque avec L·77 : \(\sum 1/R_n=9\sum d(k)/10^k=1{,}1009181908\ldots\) compte les diviseurs, \(\sum n/R_n\) les additionne, et \(\sum_p p/R_p=9\sum_k\mathrm{sopf}(k)/10^k=0{,}2093015143475853928338209\ldots\), sur les seules longueurs premières, additionne les facteurs premiers distincts (\(\mathrm{sopf}\) : 0, 2, 3, 2, 5, 5, 7, 2…), car \(\sum_p p\,x^p/(1-x^p)=\sum_k\mathrm{sopf}(k)\,x^k\). Les premiers triplés : la somme \(\sum_p\overline{ppp}/(p+p+p)\) sur les nombres premiers diverge, chaque terme valant au moins 37 ; comme le terme ne dépend que du nombre \(k\) de chiffres de \(p\) (L·120), ses inverses donnent \(\sum_p\frac{3p}{\overline{ppp}}=\sum_{k\geq1}\bigl(\pi(10^k)-\pi(10^{k-1})\bigr)\frac{3}{10^{2k}+10^k+1}=0{,}114808247015\ldots\), une constante qui encode la répartition des premiers par nombre de chiffres. Douze décimales sont garanties par les valeurs de \(\pi(10^k)\) calculées jusqu'à \(10^{11}\) et une borne du reste.

sorte loifamille arithmétique ; nombres premiers
# à 25 chiffres : Σ 1/R_n contre 9 Σ d(k)/10^k (L·77), Σ n/R_n contre 9 Σ σ(k)/10^k, Σ_p p/R_p contre 9 Σ sopf(k)/10^k ; les premières valeurs de σ et sopf ; π(10^k) jusqu'à 10^11 ; la constante des premiers triplés et la borne du reste ; le contrôle direct sur les premiers sous un million
from mpmath import mp, mpf
from sympy import divisor_sigma, primefactors, primerange, primepi, divisor_count
mp.dps = 40
R = lambda n: (10**n - 1) // 9
f25 = lambda x: mp.nstr(x, 25)
print(f25(sum(mpf(1) / R(n) for n in range(1, 120))), f25(9 * sum(mpf(int(divisor_count(k))) / mpf(10)**k for k in range(1, 120))))# 1.100918190836200736379855 1.100918190836200736379855
print(f25(sum(mpf(n) / R(n) for n in range(1, 120))), f25(9 * sum(mpf(int(divisor_sigma(k))) / mpf(10)**k for k in range(1, 120))))# 1.212956684547005893103132 1.212956684547005893103132
print(f25(sum(mpf(p) / R(p) for p in primerange(2, 120))), f25(9 * sum(mpf(sum(primefactors(k))) / mpf(10)**k for k in range(2, 120))))# 0.2093015143475853928338209 0.2093015143475853928338209
print([int(divisor_sigma(k)) for k in range(1, 13)], [sum(primefactors(k)) for k in range(1, 13)])# [1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 12, 28] [0, 2, 3, 2, 5, 5, 7, 2, 3, 7, 11, 5]
pi = [int(primepi(10**k)) for k in range(0, 12)]                 # π(10^k), k = 0..11
print(pi[1:])                 # [4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534, 455052511, 4118054813]
C = sum(mpf(pi[k] - pi[k - 1]) * 3 / (10**(2 * k) + 10**k + 1) for k in range(1, 12))
print(mp.nstr(C, 13), mp.nstr(sum(3 * mpf(10)**(-k) for k in range(12, 60)), 3))# 0.1148082470152 3.33e-12
print(mp.nstr(sum(mpf(3 * p) / int(str(p) * 3) for p in primerange(2, 10**6)), 10))# 0.1148082278
L·122la famille d'Erdős–Borwein
\(\sum_{n}\frac{w(n)}{R_n^{(b)}}\)
=
\((b-1)\sum_{k\geq1}\frac{\sum_{d\mid k}w(d)}{b^k}\)

pour une base \(b\geq2\) et un poids \(w\), où \(R_n^{(b)}=\frac{b^n-1}{b-1}\) est le répunit de \(n\) chiffres en base \(b\) : le nombre de Mersenne \(2^n-1\) en base 2, le nombre \(11\ldots1\) en base 10. La preuve tient en une ligne : \(\frac1{R_n}=(b-1)\bigl(b^{-n}+b^{-2n}+b^{-3n}+\cdots\bigr)\), et la puissance \(b^{-k}\) reçoit \(w(d)\) de chaque diviseur \(d\) de \(k\). Avec un poids nul hors des premiers, on ne garde que les diviseurs premiers. Quatre poids naturels donnent quatre fonctions arithmétiques, lisibles dans deux bases :

poidsfonction cachéebase 2 (Mersenne)base 10 (répunits)
1, toutes les longueurs\(d(k)\), nombre de diviseurs1,6066951524… (Erdős–Borwein)1,1009181908… (L·77)
n, toutes les longueurs\(\sigma(k)\), somme des diviseurs2,7440338887…1,2129566845… (L·121)
1, longueurs premières\(\omega(k)\), nombre de facteurs premiers0,5169428198…0,1000090009…
p, longueurs premières\(\mathrm{sopf}(k)\), leur somme1,3187761044…0,2093015143… (L·121)

La case en haut à gauche est la constante d'Erdős–Borwein, la somme des inverses des nombres de Mersenne : Erdős a démontré en 1948 qu'elle est irrationnelle, et Peter Borwein a étendu ce genre de résultat aux autres bases entières. En base 2, les répunits sont les nombres de Mersenne, et la ligne des longueurs premières ne garde que les \(2^p-1\), ceux qui peuvent être premiers. La colonne de droite est celle des répunits décimaux, d'où vient le tour du 37 (L·120) : multiplier par la longueur fait passer de \(d\) à \(\sigma\), et se limiter aux premiers fait passer à \(\omega\) et à \(\mathrm{sopf}\). La case \(\omega\) en base 10 a des décimales curieuses, presque uniquement des 0 et des 9 : \(\frac1{11}+\frac1{111}+\frac1{11\,111}+\cdots\), où chaque \(1/R_p=0,0\ldots09\,0\ldots09\ldots\) répète un 9 tous les \(p\) chiffres. Les deux lignes du bas mesurent les premiers à travers les diviseurs, comme le gaz de primons (L·106) ; la somme des inverses des premiers triplés (L·121) en est une cousine qui ne dépend que du nombre de chiffres.

sorte loifamille arithmétique ; nombres premiers
# les huit constantes par les deux formules, à 40 décimales près ; leurs valeurs à 25 chiffres, ligne par ligne (base 2 puis base 10) : d, σ, ω, sopf ; les premières valeurs de d et de ω ; deux contrôles en base 2 (forme de Mersenne, et σ = d + Σ 1/(2^k − 1)²)
from mpmath import mp, mpf, nstr
from sympy import divisor_count, divisor_sigma, primefactors, primerange
mp.dps = 45
K = 200                                                     # termes : erreur < b^-200
Rb = lambda n, b: mpf(b**n - 1) / (b - 1)                  # répunit en base b (b = 2 : nombre de Mersenne)
poids = {'d': (lambda n: 1, lambda k: int(divisor_count(k)), False),
         'σ': (lambda n: n, lambda k: int(divisor_sigma(k)), False),
         'ω': (lambda n: 1, lambda k: len(primefactors(k)), True),
         'sopf': (lambda n: n, lambda k: sum(primefactors(k)), True)}
def gauche(b, w, prem):                                     # Σ w(n)/R_n, sur toutes les longueurs ou les seules premières
    N = primerange(2, K) if prem else range(1, K)
    return sum(w(n) / Rb(n, b) for n in N)
def droite(b, f):                                           # (b-1) Σ f(k)/b^k : la série de Lambert dépliée
    return (b - 1) * sum(mpf(f(k)) / mpf(b)**k for k in range(1, K))
T = {(c, b): (gauche(b, w, p), droite(b, f)) for c, (w, f, p) in poids.items() for b in (2, 10)}
print(all(abs(g - d) < mpf(10)**-40 for g, d in T.values()))# True
print(nstr(T[('d', 2)][0], 25), nstr(T[('d', 10)][0], 25))# 1.606695152415291763783302 1.100918190836200736379855
print(nstr(T[('σ', 2)][0], 25), nstr(T[('σ', 10)][0], 25))# 2.744033888759488360480215 1.212956684547005893103132
print(nstr(T[('ω', 2)][0], 25), nstr(T[('ω', 10)][0], 25))# 0.5169428198056403842405166 0.1000090009090990090999091
print(nstr(T[('sopf', 2)][0], 25), nstr(T[('sopf', 10)][0], 25))# 1.318776104440764018091212 0.2093015143475853928338209
print([int(divisor_count(k)) for k in range(1, 13)], [len(primefactors(k)) for k in range(1, 13)])# [1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6] [0, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2]
print(nstr(sum(mpf(1) / (2**n - 1) for n in range(1, K)) - T[('d', 2)][0], 3), nstr(T[('σ', 2)][0] - T[('d', 2)][0] - sum(mpf(1) / (2**n - 1)**2 for n in range(1, K)), 3))# 0.0 -8.76e-46

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. L'un des problèmes du millénaire. Pourquoi le calcul ne suffit pas. Dans la formule explicite (L·70, L·107), chaque zéro \(\rho=\sigma+i\gamma\) fait apparaître un pic à la hauteur \(\gamma\), d'amplitude \(x^{\sigma-1/2}\). Sur la droite, l'amplitude reste sage ; un zéro en \(\sigma=0{,}6\) aurait son pic au même endroit, mais grossissant comme \(x^{0{,}1}\), et ne se distinguerait des autres qu'à partir d'un \(x\) gigantesque. Un zéro hors de la droite peut donc se cacher dans n'importe quel calcul fini. C'est d'ailleurs une reformulation exacte de l'hypothèse : toutes les parties réelles valent \(\frac12\) si et seulement si l'erreur dans le comptage des premiers reste de l'ordre de \(\sqrt x\), à un logarithme près (von Koch, L·75). Ce qui est démontré. La symétrie : l'équation fonctionnelle apparie chaque zéro \(\sigma+i\gamma\) avec \(1-\sigma+i\gamma\) ; un zéro hors de la droite viendrait toujours avec un jumeau en miroir, et un zéro seul est forcé sur l'axe du miroir. Le bord : aucun zéro sur \(\operatorname{Re}s=1\) (Hadamard, de la Vallée Poussin, 1896), ce qui donne le théorème des nombres premiers (L·98). Des zéros sur la droite : une infinité (Hardy, 1914), et l'on sait aujourd'hui qu'au moins 41 % des zéros y sont. Le calcul : tous les zéros de hauteur inférieure à \(3\times10^{12}\), soit plus de 12 000 milliards, sont sur la droite (Platt et Trudgian, 2021). Tout cela laisse ouverte la possibilité d'un zéro solitaire, très haut, avec son jumeau. La positivité de Weil. Weil a montré que l'hypothèse équivaut à une propriété de positivité : une certaine forme quadratique construite à partir des raies \(\ln p\), exactement la somme de L·107, doit être positive pour toutes les fonctions test. Cela traduit en langage de spectre l'idée que les zéros sont les « énergies réelles » d'un système : si les zéros sont réels, comme le seraient des énergies quantiques, la forme est positive, et réciproquement. Montrer cette positivité, c'est démontrer l'hypothèse. C'est le programme d'Alain Connes, à partir du système de Bost–Connes, le cousin rigoureux du gaz de primons (L·106). Dans le monde des corps finis, cette positivité a été démontrée (Weil pour les courbes, puis Deligne en 1974), parce que la géométrie y fournit l'opérateur. Pour les entiers, personne n'a encore trouvé l'équivalent, mais des morceaux de la positivité sont démontrés : Connes et Consani (2020) traitent le cas le plus simple, la seule « place archimédienne », sans les premiers, et minorent la forme de Weil par une trace d'opérateur pour les fonctions test portées par \([2^{-1/2},2^{1/2}]\). Le mur est le passage du local au global, toutes les fonctions test et tous les premiers à la fois. Voir aussi la constante de de Bruijn–Newman (C·7), et la marche de Mertens (L·114).

sorte conjecturefamille valeurs de ζ ; fonction Γ
# méthode de Turing jusqu'à T = 100 ; les changements de signe de la fonction Z de Hardy ; le miroir ξ(s) = ξ(1 − s) en 20 points ; puis l'ordre de grandeur où un faux zéro en σ = 0,6 deviendrait visible. Une vérification finie n'est pas une preuve.
from mpmath import mp, mpf, mpc, nzeros, zetazero, siegelz, zeta, gamma, pi, log, fsum
import random
mp.dps = 25
T = 100
print(nzeros(T))                                 # zéros dans la bande 0 < Re s < 1, 0 < Im s ≤ T# 29
k = 0
while zetazero(k + 1).imag <= T: k += 1
print(k, zetazero(1))                            # zéros trouvés sur la droite Re s = ½ (méthode de Turing)# 29 (0.5 + 14.13472514173469379045725j)
signes = [siegelz(t) > 0 for t in [mpf(j) / 50 for j in range(1, 50*T)]]
print(sum(a != b for a, b in zip(signes, signes[1:])))   # Hardy : chaque changement de signe de Z(t) est un zéro sur la droite# 29
xi = lambda s: s*(s - 1)/2 * pi**(-s/2) * gamma(s/2) * zeta(s)
random.seed(1)
pts = [mpc(random.uniform(-3, 4), random.uniform(-30, 30)) for _ in range(20)]
print(max(abs(xi(s) - xi(1 - s)) / abs(xi(s)) for s in pts) < mpf(10)**-20)   # le miroir s ↔ 1 − s# True
S = fsum(1 / abs(zetazero(j)) for j in range(1, 101))
faux = abs(mpc(0.6, 1000))
print(round(float(S), 3), f"{float((faux * S)**10):.1e}")   # un faux zéro en 0,6 + 1000i ne domine les 100 premiers zéros que pour x ≳ ce nombre# 1.031 1.4e+30
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)]
C·6une infinité de premiers primoriauxouvert
\(\#\{p : p\#+1\ \text{est premier}\}\)
\(\overset{?}{=}\)
\(\infty\)

où \(p\#=2\times3\times5\times\dots\times p\) est la primorielle (2, 6, 30, 210, 2 310…). La preuve d'Euclide de l'infinité des premiers passe par \(p\#+1\) : aucun premier jusqu'à \(p\) ne le divise, donc tous ses facteurs premiers sont nouveaux. Mais \(p\#+1\) n'est pas forcément premier lui-même : 3, 7, 31, 211, 2 311 le sont, puis \(13\#+1=30\,031=59\times509\). Côté \(p\#-1\), même chose : 5, 29, 2 309 sont premiers, mais \(7\#-1=209=11\times19\). Les premiers de ces deux formes se font rares (\(p\#+1\) n'est premier que pour \(p\) = 2, 3, 5, 7, 11, 31, 379, 1 019, 1 021… sous 1 100), et personne ne sait s'il y en a une infinité de chaque sorte, ni même s'il y a une infinité de \(p\#+1\) composés. Une heuristique de Caldwell et Gallot (2002) en prévoit une infinité, environ \(e^{\gamma}\ln x\) jusqu'à \(x\).

sources

C. K. Caldwell et Y. Gallot, « On the primality of n! ± 1 and 2 × 3 × 5 × ⋯ × p ± 1 », Mathematics of Computation 71 (2002).

sorte conjecturefamille nombres premiers
# les p ≤ 1 100 tels que p# ± 1 est premier ; les deux contre-exemples ; puis l'argument d'Euclide jusqu'à 47
from sympy import primerange, isprime, factorint
prim, plus, moins = 1, [], []
for p in primerange(2, 1100):
    prim *= p
    if isprime(prim + 1): plus.append(p)
    if isprime(prim - 1): moins.append(p)
print(plus)                                    # p tels que p# + 1 est premier# [2, 3, 5, 7, 11, 31, 379, 1019, 1021]
print(moins)                                   # p tels que p# − 1 est premier# [3, 5, 11, 13, 41, 89, 317, 337, 991]
print(factorint(30031), factorint(209))# {59: 1, 509: 1} {11: 1, 19: 1}
prim, ok = 1, True
for p in primerange(2, 48):                    # Euclide : les facteurs de p# ± 1 dépassent p
    prim *= p
    ok &= min(factorint(prim + 1)) > p and (prim == 2 or min(factorint(prim - 1)) > p)
print(ok)                     # True
C·7la constante de de Bruijn–Newman est nulleouvert
\(\Lambda\)
\(\overset{?}{=}\)
\(0\)

où \(\Lambda\) est le temps de « chauffe » à partir duquel tous les zéros de \(H_t(z)=\int_0^\infty e^{tu^{2}}\,\Phi(u)\cos(zu)\,du\) sont réels, avec le noyau \(\Phi(u)=\sum_{n\geq1}\bigl(2\pi^{2}n^{4}e^{9u}-3\pi n^{2}e^{5u}\bigr)e^{-\pi n^{2}e^{4u}}\). Au temps 0, \(H_0(z)=\frac18\,\xi\bigl(\frac12+\frac{iz}2\bigr)\), où \(\xi(s)=\frac12s(s-1)\pi^{-s/2}\Gamma(\frac s2)\zeta(s)\) : ses zéros sont \(z=2\gamma\), le double des hauteurs des zéros de Riemann. Le paramètre \(t\) agit comme une équation de la chaleur à rebours, \(\partial_tH=-\partial_z^{2}H\). De Bruijn (1950) : une fois tous les zéros réels, ils le restent pour tout \(t\) plus grand. Il existe donc un seuil \(\Lambda\), et Riemann équivaut à \(\Lambda\leq0\). Newman (1976) a conjecturé \(\Lambda\geq0\), autrement dit que Riemann, si elle est vraie, ne l'est que tout juste. Rodgers et Tao l'ont démontré en 2018. Riemann équivaut donc désormais à \(\Lambda=0\) exactement. Les bornes supérieures : \(\frac12\) (de Bruijn, 1950), \(<\frac12\) (Ki, Kim et Lee, 2009), \(0{,}22\) (Polymath 15, 2019), puis \(0{,}2\) grâce à la vérification de Riemann jusqu'à la hauteur \(3\times10^{12}\) (Platt et Trudgian, 2021). Des annonces de 2026, assistées par ordinateur, descendent à 0,179 puis 0,158, mais elles ne sont pas encore validées par une revue. On sait donc \(0\leq\Lambda\leq0{,}2\), et l'on ne connaît aucune décimale de \(\Lambda\). L'idée vient de la physique statistique : Lee et Yang (1952) ont démontré que les zéros de la fonction de partition d'un aimant d'Ising sont tous sur un cercle, un énoncé du même type que Riemann, et Newman a transposé leurs outils. Voir aussi le gaz de primons (L·106), où les zéros de Riemann sont des températures complexes interdites.

sorte conjecturefamille valeurs de ζ ; équivalent de Riemann
# le noyau Φ, positif et vite négligeable ; H₀ contre ξ/8 ; le premier zéro de H₀ en 2 × 14,1347… ; le même zéro, déplacé, à t = 0,2 ; puis l'équation de la chaleur, ∂ₜH = −∂²_z H, par différences finies
from mpmath import mp, mpf, exp, pi, cos, quad, zeta, gamma, nsum, inf, findroot, zetazero, nstr
mp.dps = 30
Phi = lambda u: nsum(lambda n: (2*pi**2*n**4*exp(9*u) - 3*pi*n**2*exp(5*u)) * exp(-pi*n**2*exp(4*u)), [1, inf])
H = lambda t, z, k=0: quad(lambda u: u**k * exp(t*u*u) * Phi(u) * cos(z*u), [0, 0.25, 0.5, 1, 1.6])
xi = lambda s: s*(s - 1)/2 * pi**(-s/2) * gamma(s/2) * zeta(s)
print([nstr(Phi(u), 6) for u in (0, 0.2, 0.5, 1)])# ['0.446697', '0.0862401', '1.37781e-7', '5.102e-70']
print(nstr(max(abs(H(0, z) - xi(mpf(1)/2 + 1j*z/2).real/8) for z in (0, 5, 10, 20)), 3))# 7.7e-34
print(nstr(findroot(lambda z: H(0, z), 28.2), 20), nstr(2*zetazero(1).imag, 20))# 28.269450283469387581 28.269450283469387581
print(nstr(findroot(lambda z: H(mpf('0.2'), z), 28.2), 12))# 28.1536122884
h = mpf('1e-6')
dHdt = (H(h, 5) - H(-h, 5)) / (2*h)              # dérivées par différences finies, indépendantes du calcul sous l'intégrale
d2Hdz2 = (H(0, 5 + h) - 2*H(0, 5) + H(0, 5 - h)) / h**2
print(nstr(dHdt, 8), nstr(-d2Hdz2, 8))# 0.00045736978 0.00045736978
C·8les marcheurs vicieux accélérésconjecture numérique, 2013
\(\alpha(N)\)
\(\overset{?}{\leq}\)
\(\frac{N(N-1)}{8}\)

où \(\alpha(N)\) est l'exposant de survie de \(N\) marcheurs vicieux dont c'est la vitesse, et non la position, qui reçoit des chocs aléatoires : \(x''(t)=\eta(t)\), un bruit blanc. La probabilité qu'aucun marcheur n'en ait rencontré un autre au temps \(t\) décroît comme \(t^{-\alpha}\). Pour les marcheurs ordinaires, \(\alpha=\frac{N(N-1)}4\) (Fisher, par la méthode des images, L·109). Pour les accélérés, la méthode des images échoue. Pour \(N=2\), \(\alpha=\frac14\) est démontré (Sinai, 1992) : l'élan fait survivre bien plus longtemps. Pour \(N=3\), le problème revient à un seul marcheur accéléré dans un coin de 60°, sans solution exacte connue ; les simulations donnent \(\alpha=0{,}71\pm0{,}01\). Xu et Schwarz (2013) conjecturent, d'après leurs simulations jusqu'à \(N=10\), que \(\frac{N(N-1)}8\), la valeur qu'on obtiendrait en multipliant naïvement les paires, est une borne supérieure, et observent que l'écart grandit avec \(N\). Statut : conjecture numérique, à notre connaissance ni démontrée ni réfutée. Ces marcheurs modélisent des brosses de polymères rigides qui ne se croisent pas, et pourraient mener à une version non markovienne du mouvement brownien de Dyson.

sorte conjecturefamille marches aléatoires ; physique statistique
# 200 000 systèmes jusqu'à t = 10 000 : l'exposant mesuré entre t = 1 000 et 10 000, et le nombre de survivants ; deux marcheurs ordinaires (1/2), deux accélérés (1/4, Sinai), trois accélérés (0,71 mesuré par Xu et Schwarz, sous la borne 0,75). Une simulation n'est pas une preuve, et avec peu de survivants la mesure est grossière
import numpy as np
rng = np.random.default_rng(1)
def survie(N, accel, M=200000, T=10000):         # M systèmes de N marcheurs, partis à distance 1
    x = np.tile(np.arange(N, dtype=float), (M, 1)); v = np.zeros((M, N)); vivant = np.ones(M, bool); s = {}
    for t in range(1, T + 1):
        i = np.nonzero(vivant)[0]
        if accel: v[i] += rng.standard_normal((len(i), N)); x[i] += v[i]
        else: x[i] += rng.standard_normal((len(i), N))
        vivant[i[np.any(np.diff(x[i], axis=1) <= 0, axis=1)]] = False
        if t in (1000, 10000): s[t] = vivant.mean()
    return round(float(-np.log(s[10000] / s[1000]) / np.log(10)), 3), int(vivant.sum())
print(survie(2, False), 0.5)  # (0.507, 2055) 0.5
print(survie(2, True), 0.25)  # (0.248, 13669) 0.25
print(survie(3, True), 0.71, 3*2/8)# (0.642, 126) 0.71 0.75
Aucune fiche ne réunit ces critères.