Partie IV - Calcul scientifique · Chapitre 21

Recherche de zéro d’une fonction

3 sections de cours · fiche d'exercices corrigee

1Dichotomie et methode de Newton

Le probleme

Etant donne \(f : [a,b] \to \mathbb R\), trouver \(\ell\) tel que \(f(\ell) = 0\).

Toute equation \(g(x) = h(x)\) se ramene a ce probleme en posant \(f = g - h\). Or la plupart des equations n'ont pas de solution exprimable : \(\cos x = x\), \(xe^x = 1\), \(x^5 - x - 1 = 0\) (theoreme d'Abel : pas de radicaux au-dela du degre 4). Le calcul approche est donc la regle, pas l'exception.

Theoreme des valeurs intermediaires

Si \(f\) est continue sur \([a,b]\) et si \(f(a)f(b) < 0\), alors il existe \(\ell \in\;]a,b[\) tel que \(f(\ell) = 0\). Si de plus \(f\) est strictement monotone, ce zero est unique.

C'est ce theoreme qui fonde la methode de dichotomie : il garantit qu'un changement de signe enferme une racine.

Methode de dichotomie

Principe

On maintient un intervalle \([a,b]\) contenant une racine (signes opposes aux bornes). A chaque etape, on evalue \(f\) au milieu \(m\) et l'on conserve la moitie ou le changement de signe persiste. La longueur de l'intervalle est divisee par 2 a chaque iteration.

def dichotomie(f, a, b, eps=1e-12, nmax=200):
    """Zero de f dans [a,b]. Precondition : f continue et f(a)*f(b) < 0.

    Renvoie (racine, nombre d'iterations).
    """
    fa, fb = f(a), f(b)
    if fa == 0: return a, 0
    if fb == 0: return b, 0
    if fa * fb > 0:
        raise ValueError("f(a) et f(b) doivent etre de signes opposes")
    n = 0
    while b - a > eps and n < nmax:
        m = (a + b) / 2
        fm = f(m)
        if fm == 0:
            return m, n
        if fa * fm < 0:
            b = m                      # le zero est dans [a, m]
        else:
            a, fa = m, fm              # il est dans [m, b]
        n += 1
    return (a + b) / 2, n

from math import cos
r, n = dichotomie(lambda x: cos(x) - x, 0, 1)
print(f"{r:.15f} en {n} iterations")     # 0.739085133215161 en 40 iterations
Analyse

Terminaison et vitesse : apres \(n\) iterations, \(b_n - a_n = \dfrac{b_0-a_0}{2^n}\), donc \[ |x_n - \ell| \le \frac{b_0-a_0}{2^{n+1}}, \qquad n \ge \log_2\!\left(\frac{b_0-a_0}{\varepsilon}\right). \] Pour \(b_0-a_0 = 1\) et \(\varepsilon = 10^{-15}\) : 50 iterations. La convergence est lineaire de rapport \(1/2\) : on gagne 1 bit, soit environ 0,3 decimale, par iteration.

Invariant : « \(f(a)f(b) < 0\), donc \([a,b]\) contient un zero de \(f\) ». Il est preserve par construction, et le variant \(b - a\) tend vers 0 : la methode est totalement correcte.

Forces et faiblesses
AvantagesInconvenients
convergence garantie sous ses hypotheseslente (lineaire)
ne demande que la continuiteexige un changement de signe (rate les racines doubles)
erreur majoree a priorine se generalise pas a la dimension superieure
insensible aux pathologies de \(f'\)n'exploite pas la regularite de \(f\)

Methode de Newton

Principe

On remplace \(f\) par sa tangente au point courant, et l'on prend pour nouvelle approximation le zero de cette tangente. La tangente en \(x_n\) a pour equation \(y = f(x_n) + f'(x_n)(x - x_n)\), qui s'annule en

\[ \boxed{\;x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}.\;} \]

def newton(f, fp, x0, eps=1e-14, nmax=100):
    """Zero de f par la methode de Newton. fp est la derivee.

    Renvoie (racine, nombre d'iterations, convergence).
    """
    x = x0
    for n in range(1, nmax + 1):
        d = fp(x)
        if d == 0:
            return x, n, False           # tangente horizontale : echec
        x_nouveau = x - f(x) / d
        if abs(x_nouveau - x) < eps * max(1.0, abs(x_nouveau)):
            return x_nouveau, n, True
        x = x_nouveau
    return x, nmax, False

from math import cos, sin
r, n, ok = newton(lambda x: cos(x) - x, lambda x: -sin(x) - 1, 1.0)
print(f"{r:.15f} en {n} iterations")     # 0.739085133215161 en 5 iterations
Theoreme de convergence quadratique

Soit \(\ell\) un zero simple de \(f\) (\(f'(\ell) \ne 0\)), \(f\) de classe \(\mathcal C^2\) au voisinage de \(\ell\). Alors il existe \(\delta > 0\) tel que, pour tout \(x_0 \in [\ell-\delta, \ell+\delta]\), la suite de Newton converge vers \(\ell\) et \[ |x_{n+1} - \ell| \;\le\; K\,|x_n - \ell|^2, \qquad K = \frac{\max|f''|}{2\min|f'|}. \]

Demonstration

La formule de Taylor-Lagrange a l'ordre 2 entre \(x_n\) et \(\ell\) donne l'existence de \(\xi\) entre les deux tels que \[ 0 = f(\ell) = f(x_n) + (\ell - x_n)f'(x_n) + \frac{(\ell-x_n)^2}{2}f''(\xi). \] En divisant par \(f'(x_n)\) (non nul au voisinage de \(\ell\)) : \[ 0 = \frac{f(x_n)}{f'(x_n)} + \ell - x_n + \frac{(\ell-x_n)^2}{2}\frac{f''(\xi)}{f'(x_n)}. \] Or \(x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}\), donc \[ \ell - x_{n+1} = -\frac{(\ell-x_n)^2}{2}\frac{f''(\xi)}{f'(x_n)}, \] d'ou \(|x_{n+1}-\ell| \le K|x_n-\ell|^2\) en majorant.

Interpretation : le nombre de decimales exactes double a chaque iteration. Partant de 1 decimale : 2, 4, 8, 16. Cinq iterations suffisent pour atteindre la precision machine.

Newton peut echouer
from math import atan
# 1. divergence : le point de depart est trop loin
r, n, ok = newton(atan, lambda x: 1/(1+x*x), 2.0)
print(ok)          # False : la suite oscille en s'eloignant

# 2. tangente horizontale
newton(lambda x: x**3 - 2*x + 2, lambda x: 3*x*x - 2, 0.0)   # cycle 0 -> 1 -> 0

# 3. racine double : convergence seulement lineaire
newton(lambda x: (x-1)**2, lambda x: 2*(x-1), 2.0)

Trois modes d'echec : divergence si \(x_0\) est mal choisi, division par zero si \(f'(x_n) = 0\), et perte de la convergence quadratique sur une racine multiple.

2Visualisation, secante et comparaison

Dichotomie et Newton, pas a pas
Choisir une fonction et une methode, puis « Initialiser ».

Methode de la secante

Newton exige de connaitre \(f'\). Quand elle est inconnue ou couteuse, on la remplace par le taux d'accroissement entre les deux derniers points :

\[ x_{n+1} = x_n - f(x_n)\,\frac{x_n - x_{n-1}}{f(x_n) - f(x_{n-1})}. \]

def secante(f, x0, x1, eps=1e-14, nmax=100):
    """Newton sans derivee. Ordre de convergence : le nombre d'or ~ 1.618."""
    f0, f1 = f(x0), f(x1)
    for n in range(1, nmax + 1):
        if f1 == f0:
            return x1, n, False
        x2 = x1 - f1 * (x1 - x0) / (f1 - f0)
        if abs(x2 - x1) < eps * max(1.0, abs(x2)):
            return x2, n, True
        x0, f0, x1, f1 = x1, f1, x2, f(x2)
    return x1, nmax, False
Ordre de la secante

L'erreur verifie \(e_{n+1} \approx K e_n e_{n-1}\). En cherchant \(e_n \approx A e_{n-1}^\alpha\), on obtient \(\alpha^2 = \alpha + 1\), donc \(\alpha = \varphi = \frac{1+\sqrt5}{2} \approx 1{,}618\) : c'est le nombre d'or.

Moins bien que Newton par iteration, mais la secante n'evalue \(f\) qu'une fois par etape contre deux (\(f\) et \(f'\)) pour Newton. A cout egal, son ordre effectif est \(\varphi^2 \approx 2{,}6 > 2\) : elle est souvent plus efficace en pratique.

Comparaison

DichotomieNewtonSecante
Ordre1 (rapport 1/2)21,618
Convergence garantieouinon (locale)non
Hypothesescontinuite, changement de signe \(\mathcal C^2\), \(f'(\ell) \ne 0\), \(x_0\) proche deux points initiaux
Evaluations par iteration1 (\(f\))2 (\(f\) et \(f'\)) 1 (\(f\))
Iterations pour \(10^{-15}\)~50~5~7
Generalisation a \(\mathbb R^n\)nonoui (jacobienne)oui (quasi-Newton)

3Methodes hybrides, criteres d'arret et applications

Methodes hybrides

Le meilleur des deux mondes

On combine la surete de la dichotomie et la vitesse de Newton : on tente un pas de Newton ; s'il sort de l'intervalle d'encadrement ou ne reduit pas assez l'erreur, on effectue un pas de dichotomie a la place.

def hybride(f, fp, a, b, eps=1e-14, nmax=100):
    """Newton securise par dichotomie. Convergence garantie ET rapide."""
    fa, fb = f(a), f(b)
    if fa * fb > 0:
        raise ValueError("pas de changement de signe")
    x = (a + b) / 2
    for n in range(1, nmax + 1):
        d = fp(x)
        pas_newton = (d != 0)
        if pas_newton:
            xn = x - f(x) / d
            pas_newton = (a < xn < b)          # le pas reste-t-il dans l'encadrement ?
        x = xn if pas_newton else (a + b) / 2   # sinon : dichotomie
        fx = f(x)
        if fx == 0 or (b - a) < eps:
            return x, n, "Newton" if pas_newton else "dichotomie"
        if fa * fx < 0:
            b = x
        else:
            a, fa = x, fx
    return x, nmax, "max atteint"

from math import atan
# atan fait diverger Newton depuis x0 = 2, mais l'hybride converge
print(hybride(atan, lambda x: 1/(1+x*x), -6, 6))

C'est le principe de la methode de Brent, utilisee par scipy.optimize.brentq : elle combine dichotomie, secante et interpolation quadratique inverse, avec convergence garantie et un ordre pratique proche de 1,8.

Choix du critere d'arret

Trois criteres, trois pieges
while abs(f(x)) > eps:        # 1. residu : trompeur si |f'| est tres petit
while abs(x1 - x0) > eps:     # 2. increment absolu : mal adapte aux grandes valeurs
while abs(x1 - x0) > eps * abs(x1):   # 3. increment relatif : le plus robuste
  • Le residu \(|f(x)|\) peut etre minuscule loin de la racine si \(f\) est tres plate : sur \(f(x) = (x-1)^7\), \(|f(1{,}1)| = 10^{-7}\) alors que l'erreur vaut \(0{,}1\).
  • L'increment absolu ne convient pas si la racine vaut \(10^{10}\) : demander \(10^{-15}\) d'increment absolu est impossible en double precision.
  • La bonne pratique combine les deux, avec un nombre maximal d'iterations pour garantir la terminaison.
def critere(x_nouveau, x, f_x, eps=1e-14, tol=1e-14):
    return (abs(x_nouveau - x) < eps * max(1.0, abs(x_nouveau))
            or abs(f_x) < tol)

Applications classiques

Racine \(k\)-ieme sans **

Pour calculer \(\sqrt[k]{A}\), on annule \(f(x) = x^k - A\). Newton donne

\[ x_{n+1} = x_n - \frac{x_n^k - A}{k x_n^{k-1}} = \frac{1}{k}\left((k-1)x_n + \frac{A}{x_n^{k-1}}\right). \]

def racine_kieme(A, k, eps=1e-15):
    """Racine k-ieme de A > 0 par Newton (methode de Heron generalisee)."""
    x = A if A > 1 else 1.0
    for _ in range(100):
        x_nouveau = ((k-1)*x + A / x**(k-1)) / k
        if abs(x_nouveau - x) < eps * x:
            return x_nouveau
        x = x_nouveau
    return x

assert abs(racine_kieme(2, 2) - 2**0.5) < 1e-14
assert abs(racine_kieme(1000, 3) - 10) < 1e-12

Pour \(k = 2\) on retrouve la methode de Heron \(x_{n+1} = \frac12(x_n + A/x_n)\), connue des Babyloniens vers 1700 av. J.-C.

Inverse sans division

Pour calculer \(1/A\) sans diviser, on annule \(f(x) = 1/x - A\), d'ou \(f'(x) = -1/x^2\) et

\[ x_{n+1} = x_n - \frac{1/x_n - A}{-1/x_n^2} = x_n(2 - Ax_n). \]

def inverse(A, x0=None, n=30):
    """1/A par Newton, sans aucune division. Convergence si 0 < x0 < 2/A."""
    x = x0 if x0 is not None else 2.0**(-A.bit_length()) if isinstance(A, int) else 0.1
    for _ in range(n):
        x = x * (2 - A*x)
    return x

print(inverse(7, 0.1), 1/7)      # 0.14285714285714285 0.14285714285714285

Cette iteration est reellement utilisee dans les processeurs : la division materielle etant lente, on calcule l'inverse par quelques iterations de Newton a partir d'une valeur initiale lue dans une table, puis on multiplie.

Point fixe et theoreme de Banach

Resoudre \(f(x) = 0\) equivaut souvent a resoudre \(g(x) = x\) pour un \(g\) bien choisi.

def point_fixe(g, x0, eps=1e-14, nmax=1000):
    """Iteration x -> g(x). Converge si g est contractante au voisinage du point fixe."""
    x = x0
    for n in range(1, nmax+1):
        y = g(x)
        if abs(y - x) < eps * max(1.0, abs(y)):
            return y, n, True
        x = y
    return x, nmax, False

from math import cos, sqrt
print(point_fixe(cos, 1.0))                     # 0.739085..., ~85 iterations
print(point_fixe(lambda x: sqrt(2 + x), 0.0))   # 2.0, ~30 iterations

Theoreme du point fixe de Banach : si \(g\) est \(k\)-lipschitzienne avec \(k < 1\) sur un intervalle stable \(I\) (c'est-a-dire \(g(I) \subset I\)), alors \(g\) admet un unique point fixe \(\ell\) dans \(I\), la suite \(x_{n+1} = g(x_n)\) converge vers \(\ell\) pour tout \(x_0 \in I\), et \[ |x_n - \ell| \le \frac{k^n}{1-k}|x_1 - x_0|. \] La convergence est lineaire de rapport \(k = |g'(\ell)|\). Newton est en fait un point fixe pour \(g(x) = x - f(x)/f'(x)\), dont on verifie que \(g'(\ell) = 0\) : c'est ce qui donne l'ordre 2.

L'essentiel du chapitre

  • Dichotomie : sure, lente (lineaire, rapport 1/2), exige un changement de signe. Erreur majoree a priori par \((b-a)/2^{n+1}\).
  • Newton : \(x_{n+1} = x_n - f(x_n)/f'(x_n)\), quadratique mais convergence seulement locale. Le nombre de decimales double a chaque etape.
  • Secante : ordre \(\varphi \approx 1{,}618\), sans derivee, souvent la plus efficace a cout egal.
  • Newton echoue sur les racines multiples (convergence lineaire), les tangentes horizontales et les mauvais points de depart.
  • Les methodes hybrides (Brent) combinent surete et vitesse.
  • Critere d'arret : increment relatif, et toujours un nombre maximal d'iterations.
Fiche d'exercices — chapitre 21Enonces gradues, du calcul d'application au niveau concours, avec corriges detailles.
Ouvrir la fiche →