Adloun

Applications : algorithmes numériques de base

Cours · Python (école d'ingénieur), chapitre 10 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun

10.1 Introduction et Motivation

Maintenant que nous maîtrisons les bases de Python ainsi que les structures conditionnelles, itératives, et les bibliothèques NumPy et Matplotlib, nous pouvons aborder nos premiers algorithmes de calcul numérique. Contrairement aux calculs sur le type int (précision arbitraire en Python), les calculs sur le type float comportent de nombreuses approximations dues au codage binaire. Ce chapitre explore comment concevoir des algorithmes robustes aux erreurs d'arrondis en abordant la comparaison de flottants, la résolution stable du second degré, la recherche de racines par dichotomie (bisection) et les méthodes classiques d'intégration numérique par quadrature.

10.2 Égalité de Flottants et Tolérances

Comme vu au Chapitre 3, deux calculs mathématiquement identiques peuvent produire des flottants légèrement différents en machine (ex. 0.1 + 0.2 != 0.3). Il est donc extrêmement risqué de baser la terminaison d'une boucle ou un test de validité sur une égalité stricte x == y.

10.2.1 Erreur Absolue vs Erreur Relative

Pour définir si deux flottants et sont proches, on peut employer :

En pratique, on combine les deux approches :

Définition 10.1Fonctions isclose
  • numpy.isclose(x, y) : (par défaut , )
  • math.isclose(x, y) (Python 3.5+) : (par défaut , )
Exemple 10.2Utilisation de isclose

import math

print(0.1 + 0.2 == 0.3) # False
print(math.isclose(0.1 + 0.2, 0.3)) # True (tolérance par défaut)
print(math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-10, abs_tol=1e-12))

10.3 Application : Résolution Stable du Second Degré

Le problème de l'égalité approchée se pose lors du calcul du discriminant d'une équation .

10.3.1 Le Problème de la Cancellation

Soit l'équation (où le discriminant théorique est nul, , admettant une racine double ).

10.3.2 Solution Numérique Stable

Pour corriger ce défaut, nous devons tester la proximité à zéro de relativement au terme . En posant une tolérance égale à l'epsilon machine (), la condition d'égalité à zéro devient :

Exemple 10.3Résolution quadratique stable

import math

def solve_quadratique_stable(a, b, c, eps=2**(-52)):
    """
    Resout ax^2 + bx + c = 0 de maniere numeriquement stable.
    """
    if abs(a) < 1e-15: # Cas dégénéré (équation linéaire)
        if abs(b) < 1e-15:
            return None # Pas d'équation
        return [-c / b]
        
    delta = b * b - 4 * a * c
    seuil = eps * b * b # Tolérance relative à b²
    
    if delta < -seuil:
        return [] # Pas de racine réelle
    elif delta > seuil:
        sqrt_delta = math.sqrt(delta)
        
        # Formule stable (évite la cancellation pour la grande racine)
        if b >= 0:
            x1 = (-b - sqrt_delta) / (2 * a)
            x2 = (2 * c) / (-b - sqrt_delta)
        else:
            x1 = (-b + sqrt_delta) / (2 * a)
            x2 = (2 * c) / (-b + sqrt_delta)
        return sorted([x1, x2])
    else:
        # Racine double (discriminant proche de zéro)
        return [-b / (2 * a)]

# Test
print(solve_quadratique_stable(0.01, 0.2, 1)) # [-10.0]
print(solve_quadratique_stable(1, -3, 2)) # [1.0, 2.0]

10.4 Recherche de Racine par Dichotomie

La méthode de dichotomie (bisection) est un algorithme robuste permettant de trouver une solution approchée à l'équation pour une fonction continue sur un intervalle .

10.4.1 Principe et Algorithme

Le théorème des valeurs intermédiaires (TVI) assure que si et sont de signes opposés (), alors il existe au moins une racine telle que .

L'algorithme de dichotomie construit deux suites de bornes et telles que :

10.4.2 Analyse de l'Erreur et Convergence

La largeur de l'intervalle est divisée par 2 à chaque étape :

L'invariant de boucle est , ce qui garantit la présence d'une racine dans .

Si l'on s'arrête lorsque , alors l'approximation finale vérifie .

Le nombre d'itérations nécessaire pour atteindre cette précision satisfait :

10.4.3 Implémentation Python Sécurisée

Exemple 10.4Algorithme de dichotomie

def dichotomie(f, a, b, epsilon=1e-12, maxiter=100):
    """
    Recherche une racine de f par dichotomie sur [a, b].
    
    Paramètres:
    f : fonction continue
    a, b : bornes de l'intervalle (f(a)*f(b) <= 0)
    epsilon : précision souhaitée
    maxiter : nombre maximal d'itérations
    
    Retourne:
    Approximation de la racine
    """
    if f(a) * f(b) > 0:
        raise ValueError("f(a) et f(b) doivent être de signes opposés")
        
    u, v = a, b
    for n in range(maxiter):
        w = (u + v) / 2
        if abs(v - u) <= 2 * epsilon:
            return w
            
        if f(u) * f(w) <= 0:
            v = w
        else:
            u = w
            
    raise RuntimeError(f"Non convergence après {maxiter} itérations")

# Exemple : racine de x^2 - 2 (sqrt(2)) sur [1, 2]
f = lambda x: x**2 - 2
racine = dichotomie(f, 1, 2, epsilon=1e-12)
print(f"sqrt(2) = {racine:.12f}")

10.4.4 Méthode de Newton (Convergence Quadratique)

Lorsque la dérivée est disponible, la méthode de Newton offre une convergence quadratique.

Exemple 10.5Méthode de Newton

def newton(f, df, x0, epsilon=1e-12, maxiter=100):
    """
    Recherche une racine de f par la méthode de Newton.
    
    Paramètres:
    f : fonction
    df : dérivée de f
    x0 : approximation initiale
    epsilon : précision souhaitée
    maxiter : nombre maximal d'itérations
    """
    x = x0
    for n in range(maxiter):
        fx = f(x)
        if abs(fx) < epsilon:
            return x
        dfx = df(x)
        if abs(dfx) < 1e-15:
            raise RuntimeError("Dérivée nulle")
        x = x - fx / dfx
    raise RuntimeError(f"Non convergence après {maxiter} itérations")

# Exemple : sqrt(2) par Newton
f = lambda x: x**2 - 2
df = lambda x: 2*x
racine_newton = newton(f, df, 1.5)
print(f"sqrt(2) (Newton) = {racine_newton:.12f}")

10.4.5 Utilisation de SciPy

Exemple 10.6Recherche de racines avec SciPy

from scipy.optimize import bisect, newton

# Dichotomie SciPy
racine_bisect = bisect(lambda x: x**2 - 2, 1, 2, xtol=1e-12)

# Newton SciPy
racine_newton_sp = newton(lambda x: x**2 - 2, 1.5)

print(f"SciPy bisect : {racine_bisect:.12f}")
print(f"SciPy newton : {racine_newton_sp:.12f}")

10.5 Intégration Numérique (Méthodes de Quadrature)

Le calcul analytique d'une intégrale définie est parfois complexe ou impossible. Les méthodes de quadrature approchent cette intégrale par une somme pondérée finie de valeurs de la fonction :

Pour calculer l'intégrale sur un grand intervalle , on le subdivise en sous-intervalles de taille délimités par les points (ou selon la notation).

10.5.1 Méthode du Rectangle (Gauche et Droite)

La méthode du rectangle à gauche sur un intervalle élémentaire approxime la fonction par sa valeur sur la borne inférieure :

La méthode du rectangle à droite utilise la borne supérieure :

◆Théorème 10.7Erreur du Rectangle Élémentaire

Si est de classe sur , alors l'erreur vérifie :

où .

Formules composites :

où . L'erreur globale est en : .

Exemple 10.8Rectangle gauche et droit

def rectangle_gauche(f, a, b, n):
    h = (b - a) / n
    x = np.linspace(a, b - h, n)
    return h * np.sum(f(x))

def rectangle_droit(f, a, b, n):
    h = (b - a) / n
    x = np.linspace(a + h, b, n)
    return h * np.sum(f(x))

10.5.2 Méthode du Point Milieu

La méthode du point milieu approche l'intégrale en évaluant la fonction au centre de l'intervalle :

◆Théorème 10.9Erreur du Point Milieu

Si est de classe sur , alors l'erreur vérifie :

où . La méthode est d'ordre 2.

Formule composite :

L'erreur globale est en : .

Exemple 10.10Méthode du point milieu

def point_milieu(f, a, b, n):
    h = (b - a) / n
    x = np.linspace(a + h/2, b - h/2, n)
    return h * np.sum(f(x))

10.5.3 Méthode des Trapèzes

La méthode des trapèzes approxime la fonction par la fonction affine joignant et :

◆Théorème 10.11Erreur du Trapèze Élémentaire

Si est de classe sur , alors l'erreur vérifie :

La méthode est d'ordre 2.

Formule composite :

L'erreur globale est en : .

Exemple 10.12Méthode des trapèzes

def trapezes(f, a, b, n):
    h = (b - a) / n
    x = np.linspace(a, b, n+1)
    return h * (np.sum(f(x)) - (f(a) + f(b))/2)

10.5.4 Méthode de Simpson

La méthode de Simpson approche la fonction par le polynôme de degré 2 passant par , et :

◆Théorème 10.13Erreur de Simpson

Bien que basée sur une interpolation quadratique (degré 2), la méthode de Simpson est d'ordre 4 (exacte pour les polynômes de degré ). Si est de classe sur , alors :

où .

Formule composite ( doit être pair) :

L'erreur globale est en : .

La suite du cours est sur Adloun

Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.

Lire la suite du cours

En accès libre, sans inscription.

Exercices corrigés de ce chapitre

Lire la suite du cours →