{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cef0b037",
   "metadata": {},
   "source": [
    "$\\newcommand\\N{\\mathbb N}\n",
    "\\newcommand\\Z{\\mathbb Z}\n",
    "\\newcommand\\Q{\\mathbb Q}\n",
    "\\newcommand\\R{\\mathbb R}\n",
    "\\newcommand\\C{\\mathbb C}\n",
    "\\newcommand\\too\\longrightarrow\n",
    "\\renewcommand\\phi\\varphi\n",
    "\\renewcommand\\epsilon\\varepsilon\n",
    "\\renewcommand\\hat\\widehat\n",
    "\\renewcommand\\tilde\\widetilde\n",
    "\\renewcommand\\vec\\overrightarrow\n",
    "\\renewcommand\\bar\\overline\n",
    "\\newcommand\\fl[1]{\\left\\lfloor #1\\right\\rfloor}\n",
    "\\newcommand\\llbracket{[\\![}\n",
    "\\newcommand\\rrbracket{]\\!]}\n",
    "\\newcommand\\bbr[2]{\\llbracket #1,#2\\rrbracket}\n",
    "\\newcommand\\todo{{\\bf TODO }}\n",
    "\\newcommand\\prob{\\mathbb P}\n",
    "\\newcommand\\esp{\\mathbb E}\n",
    "\\newcommand\\var{\\mathbb V}\n",
    "\\newcommand\\tribu{\\mathfrak T}$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "feda6f07",
   "metadata": {},
   "source": [
    "# Polynômes et nombres de Bernoulli\n",
    "\n",
    "Marc Lorenzi\n",
    "\n",
    "1er mai 2026"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8321d2ba",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from fractions import Fraction\n",
    "import math"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c249c1c8",
   "metadata": {},
   "source": [
    "## 1. Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f12d813b",
   "metadata": {},
   "source": [
    "### 1.1 Définitions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68701aa8",
   "metadata": {},
   "source": [
    "<div style=\"border: 1px solid black; padding: 10px;background-color:#FFFFCC;color:#000000;border-radius:10px;\" >\n",
    "    <b>Définition.</b> La suite $(B_n)_{n\\in\\N}$ des <i>polynômes de Bernoulli</i> est définie par $B_0=1$ et pour tout $n\\in\\N^*$, \n",
    "$$B'_n=nB_{n-1}\\,{\\rm et}\\, \\int_0^1B_n=0$$<br>\n",
    "Pour tout $n\\in\\N$, le $n^e$ <i>nombre de Bernoulli</i> est $b_n=B_n(0)$.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08576e4c",
   "metadata": {},
   "source": [
    "<div style=\"border: 1px solid black; padding: 10px;background-color:#CCFFCC;color:#000000;border-radius:10px;\" >\n",
    "    <b>Proposition 1.</b> Pour tout $n\\in\\N$,\n",
    "\n",
    "$$B_n=\\sum_{k=0}^n\\binom n kb_{k}X^{n-k}$$\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36357a74",
   "metadata": {},
   "source": [
    "**Démonstration.** Faisons une récurrence sur $n$. Tout d'abord,\n",
    "\n",
    "$$B_0=b_0=\\sum_{k=0}^0\\binom 0 kb_kX^{0-k}$$\n",
    "\n",
    "Soit $n\\in\\N^*$. Supposons la propriété vraie pour $n-1$. Par HR,\n",
    "\n",
    "$$B'_{n}=nB_{n-1}=n\\sum_{k=0}^{n-1}\\binom{n-1}kb_{k}X^{n-1-k}$$\n",
    "\n",
    "De là,\n",
    "\n",
    "\\begin{eqnarray*}\n",
    "B_{n}&=&B_{n}(0)+n\\sum_{k=0}^{n-1}\\frac 1{n-k}\\binom{n-1}kb_{k}X^{n-k}\n",
    "\\end{eqnarray*}\n",
    "\n",
    "Remarquons que pour tout $k\\in\\bbr0{n-1}$,\n",
    "\n",
    "$$\\frac n{n-k}\\binom{n-1}k=\\frac n{n-k}\\frac{(n-1)!}{k!(n-1-k)!}=\\frac{n!}{k!(n-k)!}=\\binom n k$$\n",
    "\n",
    "On a donc\n",
    "\n",
    "$$B_{n}=b_{n}+\\sum_{k=0}^{n-1}\\binom n kb_{k}X^{n-k}=\\sum_{k=0}^{n}\\binom n kb_{k}X^{n-k}$$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e6e9630",
   "metadata": {},
   "source": [
    "### 1.2 Relation de récurrence"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6a61760",
   "metadata": {},
   "source": [
    "<div style=\"border: 1px solid black; padding: 10px;background-color:#CCFFCC;color:#000000;border-radius:10px;\" >\n",
    "    <b>Proposition 2.</b> Pour tout $n\\ge 1$,\n",
    "\n",
    "$$\\sum_{k=0}^{n}\\binom{n+1}kb_k=0$$\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd30f070",
   "metadata": {},
   "source": [
    "**Démonstration.** Soit $n\\in\\N$. On a, par la proposition 1,\n",
    "\n",
    "\\begin{eqnarray*}\n",
    "\\int_0^1B_n(t)\\,dt&=&\\sum_{k=0}^n\\binom n kb_{k}\\int_0^1t^{n-k}\\,dt\\\\\n",
    "&=&\\sum_{k=0}^n\\binom n k\\frac{b_k}{n-k+1}\\\\\n",
    "&=&\\frac 1{n+1}\\sum_{k=0}^n\\binom{n+1}kb_k\n",
    "\\end{eqnarray*}\n",
    "\n",
    "Si $n\\ge1$, cette intégrale et nulle, et donc\n",
    "$$\\sum_{k=0}^n\\binom{n+1}kb_k=0$$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e4173a4",
   "metadata": {},
   "source": [
    "**Remarque.**  On retrouve l'égalité montrée dans le DM 15 sur les développements limités."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd7b6f6e",
   "metadata": {},
   "source": [
    "### 1.3 Le calcul des nombres de Bernoulli"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f114a2a1",
   "metadata": {},
   "source": [
    "Connaissant $b_0,\\ldots,b_{n-1}$, la relation de récurrence de la proposition 2 permet le calcul de $b_n$.\n",
    "\n",
    "La fonction `liste_bernoulli` renvoie la liste $[b_0,\\ldots,b_N]$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a58e0432",
   "metadata": {},
   "outputs": [],
   "source": [
    "def step_binom(s):\n",
    "    n = len(s)\n",
    "    return [1] + [s[k] + s[k + 1] for k in range(n - 1)] + [1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a4d33054",
   "metadata": {},
   "outputs": [],
   "source": [
    "s = [1]\n",
    "for k in range(6):\n",
    "    s = step_binom(s)\n",
    "    print(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "803b124d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def liste_bernoulli(N):\n",
    "    s = [1, 2, 1]\n",
    "    bs = [Fraction(1)]\n",
    "    for n in range(1, N + 1):\n",
    "        b = 0\n",
    "        for k in range(n):\n",
    "            b = b + s[k] * bs[k]\n",
    "        bs.append(-Fraction(b, n + 1))\n",
    "        s = step_binom(s)\n",
    "    return bs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6dbbb3a0",
   "metadata": {},
   "outputs": [],
   "source": [
    "bs = liste_bernoulli(12)\n",
    "for k in range(13):\n",
    "    print('%3d%20s' % (k, bs[k]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5db802ef",
   "metadata": {},
   "source": [
    "**Remarque.** Voir DM numéro 15, question I.2. On y retrouve les valeurs des $b_n$ pour $n\\in\\bbr04$."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "042a84a2",
   "metadata": {},
   "source": [
    "## 2. Le graphe des polynômes de Bernoulli"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fcccfd48",
   "metadata": {},
   "source": [
    "### 2.1 Évaluer $B_n$ en un point"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41ff2b0c",
   "metadata": {},
   "source": [
    "La fonction `liste_binom` renvoie la liste des $\\binom n k$ pour $k\\in\\bbr0n$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dac3042b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def liste_binom(n):\n",
    "    s = [1]\n",
    "    for k in range(n):\n",
    "        s = step_binom(s)\n",
    "    return s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec8e308a",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(liste_binom(6))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75a6dbaf",
   "metadata": {},
   "source": [
    "La fonction `coefs_bernoulli` renvoie la liste des coefficients du polynôme $B_n$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "301b1482",
   "metadata": {},
   "outputs": [],
   "source": [
    "def coefs_bernoulli(n):\n",
    "    cs = liste_binom(n)\n",
    "    bs = liste_bernoulli(n)\n",
    "    return [bs[n - k] * cs[k] for k in range(n + 1)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f9df709",
   "metadata": {},
   "outputs": [],
   "source": [
    "coefs_bernoulli(4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e48b5956",
   "metadata": {},
   "source": [
    "La fonction `eval_poly` renvoie $P(x)$ où $P$ est donné par la liste `cs` de ses coefficients. Elle utilise l'algorithme de Horner."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94d8b053",
   "metadata": {},
   "outputs": [],
   "source": [
    "def eval_poly(x, cs):\n",
    "    n = len(cs) - 1\n",
    "    s = 0\n",
    "    for k in range(n + 1):\n",
    "        s = x * s + cs[n - k]\n",
    "    return s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7144609a",
   "metadata": {},
   "outputs": [],
   "source": [
    "eval_poly(2, [1, 2, 3, 4])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4185e05",
   "metadata": {},
   "source": [
    "### 2.2 Graphes"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e509a89a",
   "metadata": {},
   "source": [
    "Traçons les polynômes $B_n$. La partie intéressante de la courbe se trouve dans le segment $[0,1]$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "341f4bae",
   "metadata": {},
   "outputs": [],
   "source": [
    "def subdi(a, b, n):\n",
    "    d = (b - a) / n\n",
    "    return [a + k * d for k in range(n + 1)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70e1841c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def tracer_polyB(ns):\n",
    "    xs = subdi(0, 1, 1000)\n",
    "    for n in ns:\n",
    "        cs = coefs_bernoulli(n)\n",
    "        ys = [eval_poly(x, cs) for x in xs]\n",
    "        plt.plot(xs, ys, 'k', lw=1)\n",
    "    plt.grid()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11d9511f",
   "metadata": {},
   "source": [
    "Regardons le graphe des $B_n$ pour $n$ impair. Si $n$ est impair et différent de 1, $B_n(0)=B_n(1/2)=B_n(1)=0$. De plus, $0$, $1/2$ et $1$ sont les seules racines de $B_n$ sur $[0,1]$. En fait, les graphes de tous les $B_n$ pour $n$ impair ont la même allure (faire l'expérience dans la cellule ci-dessous). Ils sont symétriques par rapport au point $(1/2,0)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bac1d892",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = (8, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "77e6539d",
   "metadata": {},
   "outputs": [],
   "source": [
    "tracer_polyB([3, 5, 7, 9, 11])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d30ccd27",
   "metadata": {},
   "source": [
    "Regardons maintenant le graphe des $B_n$ pour $n$ pair. Si $n\\equiv 0\\bmod 4$, $B_n$ croît strictement sur $[0,1/2]$ puis décroît strictement sur $[1/2,1]$. Si $n\\equiv 2\\bmod 4$, c'est le contraire. Les graphes sont symétriques par rapport à la droite d'équation $x=1/2$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ab0efec",
   "metadata": {},
   "outputs": [],
   "source": [
    "tracer_polyB([2, 4, 6, 8, 10, 12])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7bef7f9",
   "metadata": {},
   "source": [
    "### 2.3 Racines"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e77fdba0",
   "metadata": {},
   "source": [
    "On peut démontrer que si $n$ est pair, $B_n$ a une unique racine sur $]0,1/2[$. Calculons une valeur approchée de cette racine par dichotomie."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5718d0cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "def approx_racineB(n, eps=1e-10):\n",
    "    a, b = 0, 1/2\n",
    "    cs = coefs_bernoulli(n)\n",
    "    while b - a > eps:\n",
    "        c = (a + b) / 2\n",
    "        if eval_poly(a, cs) * eval_poly(c, cs) <= 0: b = c\n",
    "        else: a = c\n",
    "    return (a + b) / 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b7c48c83",
   "metadata": {},
   "outputs": [],
   "source": [
    "for n in range(2, 31, 2):\n",
    "    print('%3d%20.15f' % (n, approx_racineB(n)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb73ee35",
   "metadata": {},
   "source": [
    "Se pourrait-il que lorsque $n$ tend vers l'infini, cette racine tende vers $1/4$ ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "239dcb69",
   "metadata": {},
   "source": [
    "## 3. La fonction zeta de Riemann"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b3b914f",
   "metadata": {},
   "source": [
    "Pour tout $s\\in\\C$ tel que $\\text{Re}(s)>1$, la série de Riemann de paramètre $s$ converge absolument. On pose\n",
    "\n",
    "$$\\zeta(s)=\\sum_{n=1}^\\infty \\frac 1{n^s}$$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "411ada4a",
   "metadata": {},
   "source": [
    "<div style=\"border: 1px solid black; padding: 10px;background-color:#CCFFCC;color:#000000;border-radius:10px;\" >\n",
    "    <b>Proposition 3.</b> Pour tout $n\\in\\N^*$,\n",
    "\n",
    "$$\\zeta(2n)=(-1)^{n-1}\\frac{2^{2n-1}b_{2n}}{(2n)!}\\pi^{2n}$$\n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47f0fbd0",
   "metadata": {},
   "source": [
    "**Démonstration.** C'est le but du DM 17."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "66a05831",
   "metadata": {},
   "outputs": [],
   "source": [
    "def fact(n):\n",
    "    p = 1\n",
    "    for k in range(1, n + 1):\n",
    "        p = p * k\n",
    "    return p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c69b1ab3",
   "metadata": {},
   "outputs": [],
   "source": [
    "print([fact(n) for n in range(11)])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5a01535",
   "metadata": {},
   "source": [
    "La fonction `zeta` prend en paramètre un entier $n$ pair. Elle renvoie $\\zeta(n)/\\pi^{n}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11c5364d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def zeta(n):\n",
    "    assert n % 2 == 0\n",
    "    bs = liste_bernoulli(n)\n",
    "    return Fraction(2 ** (n - 1) * (-1) ** (n // 2 - 1) * bs[n], fact(n))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d17916e1",
   "metadata": {},
   "source": [
    "Affichons la valeur exacte de $\\zeta(n)$ ainsi qu'une valeur approchée de $\\zeta(n)$, pour quelques valeurs de $n$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6e0bc2a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "for n in range(2, 21, 2):\n",
    "    print('%3d%30s π^%2d%20.15f' % (n, zeta(n), n, float(zeta(n) * math.pi ** n)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7950b2b2",
   "metadata": {},
   "source": [
    "La dernière question du DM 17 demande de calculer $\\zeta(100)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a35b2a89",
   "metadata": {},
   "outputs": [],
   "source": [
    "n = 100\n",
    "print('%s π^%2d' % (zeta(n), n))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9917580",
   "metadata": {},
   "source": [
    "## 4. Un équivalent de $b_{2n}$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0b063f6",
   "metadata": {},
   "source": [
    "<div style=\"border: 1px solid black; padding: 10px;background-color:#CCFFCC;color:#000000;border-radius:10px;\" >\n",
    "    <b>Proposition 4.</b> $\\lim_{s\\to\\infty}\\zeta(s)=1$.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cdd8c9ff",
   "metadata": {},
   "source": [
    "**Démonstration.** Pour tout réel $s>1$, posons $f(s)=\\zeta(s)-1$. Il s'agit de montrer que $f$ tend vers 0 en $+\\infty$. On a pour tout $s>1$,\n",
    "\n",
    "$$f(s)=\\sum_{n=2}^\\infty\\frac 1{n^s}$$\n",
    "\n",
    "Facilement, la fonction $f$ est positive et décroissante sur $]1,+\\infty[$. Elle a donc une limite $\\ell\\ge 0$ en $+\\infty$. Pour tout $s>1$,\n",
    "\n",
    "$$f(s+1)=\\sum_{n=2}^\\infty\\frac 1 n\\frac 1{n^s}\\le\\frac 1 2\\sum_{n=2}^\\infty\\frac 1{n^s}=\\frac 1 2f(s)$$\n",
    "\n",
    "En passant à la limite lorsque $n$ tend vers l'infini, on obtient\n",
    "\n",
    "$$\\ell\\le\\frac 1 2\\ell$$\n",
    "\n",
    "d'où $\\ell\\le 0$. Comme $\\ell\\ge 0$, on a finalement $\\ell=0$."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "466abaaf",
   "metadata": {},
   "source": [
    "<div style=\"border: 1px solid black; padding: 10px;background-color:#CCFFCC;color:#000000;border-radius:10px;\" >\n",
    "    <b>Corollaire 5.</b>\n",
    "\n",
    "$$b_{2n}\\sim4(-1)^{n-1}\\left(\\frac n{\\pi e}\\right)^{2n}\\sqrt{\\pi n}$$\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b522fcb3",
   "metadata": {},
   "source": [
    "**Démonstration.** Il suffit d'utiliser les propositions 3 et 4, puis la formule de Stirling.\n",
    "\n",
    "Ci-dessous la valeurs du quotient de $b_{2n}$ par l'équivalent pour $n\\le 50$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "de7ca706",
   "metadata": {},
   "outputs": [],
   "source": [
    "bs = liste_bernoulli(101)\n",
    "for n in range(1, 51):\n",
    "    equiv = 4 * (-1) ** (n - 1) * (n / math.pi / math.e) ** (2 * n) * math.sqrt(math.pi * n)\n",
    "    print('%3d%+20.10e' % (n, float(bs[2 * n]) / equiv))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9ef097e5",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
