From f6c69efb16672d190588ed82fd579887a1d2265b Mon Sep 17 00:00:00 2001 From: Namu Date: Sun, 18 Jan 2026 23:47:06 +0100 Subject: [PATCH] =?UTF-8?q?Refactor:=20Ajoute=20de=20la=20documentation=20?= =?UTF-8?q?et=20de=20nouvelle=20impl=C3=A9mentation=20pour=20les=20m=C3=A9?= =?UTF-8?q?thodes=20de=20calcul=20d'intervalle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tp6.py | 6 +++ tp7.py | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- tp8.py | 26 +++++++++++++ 3 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 tp8.py diff --git a/tp6.py b/tp6.py index 9fd5df7..b224154 100644 --- a/tp6.py +++ b/tp6.py @@ -123,6 +123,12 @@ def exercice2() -> None: def moindre_carre(points: list[Point]) -> np.ndarray[np.float64]: + """ + + :param points: + :return: Le vecteur contenant les coefficients du polynome + """ + # Construction de la matrice A et du vecteur y T = np.array([p.x for p in points]) Y = np.array([p.y for p in points]) diff --git a/tp7.py b/tp7.py index cee7cec..d3a68cf 100644 --- a/tp7.py +++ b/tp7.py @@ -10,14 +10,14 @@ def trapeze_formule(f, a: float, b: float, n: int) -> float: :param f: la fonction f (bien passer une fonction ou une lambda) :param a: la petite borne :param b: la grande borne - :param n: nombre de "tranche" de calcul - :return: + :param n: nombre de "tranche" dans l'intervalle + :return: l'approximation de la valeur de l'intervalle """ - # dx = (b-a) / n + # largeur de chaque sous-intervalle dx = (b - a) / n - # somme_inferieure = sum de i = 1 jusqu'a n - 1 faire f(xi) + # la somme des valeurs de f aux points entre a et b, f(a) f(b) exclus somme_inferieure = 0. for i in range(1, n): @@ -28,11 +28,37 @@ def trapeze_formule(f, a: float, b: float, n: int) -> float: I = (dx / 2) * (f(a) + f(b) + 2 * somme_inferieure) return I +def trapeze_version_numpy(f, a: float, b: float, n: int) -> float: + """ + + :param f: la fonction f (bien passer une fonction ou une lambda) + :param a: la petite borne + :param b: la grande borne + :param n: nombre de "tranche" dans l'intervalle + :return: l'approximation de la valeur de l'intervalle + """ + + # largeur de chaque sous-intervalle + dx = (b - a) / n + x = np.linspace(a, b, n+1) + y = f(x) + return dx * (np.sum(y) - 0.5*(y[0] + y[-1])) + def simpson(f, a: float, b: float, n: int) -> float: + """ + + :param f: la fonction f(x) + :param a: la petite borne + :param b: la grande borne + :param n: nombre de "tranche" dans l'intervalle + :return: l'approximation de la valeur de l'intervalle + """ + if n % 2 != 0: raise ValueError(f'n must be even, got {n}') + # largeur de chaque sous-intervalle dx = (b - a) / n somme_paire = 0. @@ -48,6 +74,23 @@ def simpson(f, a: float, b: float, n: int) -> float: I = (dx / 3) * (f(a) + f(b) + 4 * somme_impaire + 2 * somme_paire) return I + +def simpson_numpy(f, a: float, b: float, n: int) -> float: + if n % 2 != 0: + raise ValueError(f'n must be even, got {n}') + + # largeur de chaque sous-intervalle + dx = (b - a) / n + x = np.linspace(a, b, n + 1) + y = f(x) + + coefficients = np.ones(n + 1) # Crée un tableau de 1.0 de taille n+1 + coefficients[1:n:2] = 4 # Remplace les indices impairs (1, 3, 5, ...) par 4 + coefficients[2:n:2] = 2 # Remplace les indices pairs (2, 4, 6, ...) par 2 + + return (dx / 3) * np.sum(coefficients * y) + + # Les b possibles dans Newton Cotes POIDS = { 2: [1/2,1/2], @@ -65,7 +108,18 @@ POIDS = { } def newton_cotes(f, a: float, b: float, s: int, n: int) -> float: - weights = POIDS[s+1] # Poids pour l'ordre s + """ + + :param f: la fonction f(x) + :param a: la petite borne + :param b: la grande borne + :param s: l'ordre (faire +1 pour savoir quel poid utiliser) Cela détermine comme on approxime la courbe de la fonction + Une courbe (méthode des trapèzes), un polynôme de deg. 2 (Simpson), etc. + :param n: Nombre de "tranche" dans l'intervalle + :return: l'approximation de la valeur de l'intervalle + """ + + weights = POIDS[s+1] # Poids pour l'ordre "s" h = (b - a) / n Aj = 0. @@ -81,6 +135,47 @@ def newton_cotes(f, a: float, b: float, s: int, n: int) -> float: return Aj +def newton_cotes_numpy(f, a: float, b: float, s: int, n: int) -> float: + """ + Approximation de l'intégrale de f sur [a, b] par la formule de Newton-Cotes d'ordre s. + + :param f: Fonction à intégrer. + :param a: Borne inférieure. + :param b: Borne supérieure. + :param s: Ordre de la formule (1: trapèzes, 2: Simpson, etc.). + :param n: Nombre de sous-intervalles (doit être divisible par s pour les formules fermées). + :return: Approximation de l'intégrale. + """ + + if n % s != 0: + raise ValueError(f'n must be a multiple of s, got s = {s} and n = {n}') + + # b_i dans le tableau + weights_by_orders = { + 2: [1 / 2, 1 / 2], # trapèzes + 3: [1 / 6, 4 / 6, 1 / 6], # simpson + 4: [1 / 8, 3 / 8, 3 / 8, 1 / 8], # simpson 3/8 + 5: [ + 7 / 90, + 32 / 90, + 12 / 90, + 32 / 90, + 7 / 90, + ], # bool + 6: [19 / 288, 75 / 288, 50 / 288, 50 / 288, 75 / 255, 19 / 255], + 7: [41 / 840, 216 / 840, 27 / 840, 272 / 840, 27 / 840, 216 / 840, 41 / 840] + } + + weights = weights_by_orders[s+1] + h = (b - a) / n + x = np.linspace(a, b, n * s + 1) # Tous les points d'évaluation + y = f(x) + + # Applique les poids de manière glissante sur chaque sous-intervalle + return np.sum( + np.convolve(y, weights[::-1], mode='valid') * (h / (s + 1)) # Convolution pour appliquer les poids + ) + def exercice1(): f = lambda x: x ** 2 @@ -91,9 +186,21 @@ def exercice1(): trapeze1 = trapeze_formule(g, a=0, b=np.pi, n=100) trapeze2 = trapeze_formule(g, a=0, b=np.pi, n=200) + giga_trapeze1 = trapeze_version_numpy(g, 0, np.pi, 100) + giga_trapeze2 = trapeze_version_numpy(g, 0, np.pi, 200) + + print(f'VERSION MOI {trapeze1}, VERSION CHAT {giga_trapeze1}') + print(f'VERSION MOI {trapeze2}, VERSION CHAT {giga_trapeze2}') + simpson1 = simpson(g, a=0, b=np.pi, n=100) simpson2 = simpson(g, a=0, b=np.pi, n=200) + giga_simpson1 = simpson_numpy(g, 0, np.pi, 100) + giga_simpson2 = simpson_numpy(g, 0, np.pi, 200) + + print(f'MOI: {simpson1}, CHAT : {giga_simpson1}') + print(f'MOI: {simpson2}, CHAT : {giga_simpson2}') + newton1 = newton_cotes(g, a=0, b=np.pi, n=100, s=4) newton2 = newton_cotes(g, a=0, b=np.pi, n=200, s=4) @@ -146,5 +253,5 @@ def exercice2(): if __name__ == '__main__': - #exercice1() - exercice2() + exercice1() + #exercice2() diff --git a/tp8.py b/tp8.py new file mode 100644 index 0000000..7188770 --- /dev/null +++ b/tp8.py @@ -0,0 +1,26 @@ +import matplotlib.pyplot as plt + + +def euler(f, n: int, delta_x: float, x_0: float, y_0: float) -> list[float]: + results = [] + + x = x_0 + y = y_0 + for i in range(n): + x = x + delta_x + y = y + delta_x * f(x, y) + results.append(y) + + return results + + +def exercice1() -> None: + f = lambda x, y: -2 * x * y + 1 + results = euler(f, n=20, x_0=0, y_0=1, delta_x=.2) + plt.plot(results) + plt.title('Euler') + plt.show() + + +if __name__ == '__main__': + exercice1()