Les équations du second degré, ou équations quadratiques, sont très faciles à résoudre mathématiquement, mais dès lors que l’on souhaite écrire un programme en Python permettant de les résoudre, c’est autre chose…
J’ai voulu testé deux manières de concevoir un programme de résolution des équations quadratiques à l’aide de l’intelligence artificielle après avoir moi-même écrit un programme, histoire de comparer…
Alors oui, je sais, j’ai déjà écrit un article sur ce thème, mais je faisais appel à Xcas. Je voudrais maintenant être le plus autonome possible et donc ne me contenter que d’une solution Python pure.
Conception d’un programme avec ChatGPT
Le prompt que j’ai saisi sur chatGPT est le suivant:
Peux-tu me donner un programme écrit en Python qui permet de résoudre une équation du second degré sur l'ensemble des nombres réels ?
Et voici sa réponse:
import math def solve_quadratic(a, b, c): discriminant = b**2 - 4*a*c if discriminant > 0: root1 = (-b + math.sqrt(discriminant)) / (2*a) root2 = (-b - math.sqrt(discriminant)) / (2*a) return root1, root2 elif discriminant == 0: root = -b / (2*a) return root else: return None # Exemple d'utilisation a = float(input("Entrez le coefficient a : ")) b = float(input("Entrez le coefficient b : ")) c = float(input("Entrez le coefficient c : ")) solutions = solve_quadratic(a, b, c) if solutions is None: print("Pas de solution réelle.") elif isinstance(solutions, tuple): print("Les solutions sont :", solutions[0], "et", solutions[1]) else: print("La solution est :", solutions)
Ce code ne me convient pas car il ne donne que les valeurs approchées des solutions quand le discriminant n’est pas un carré parfait.
Au fait, pour plus de détail sur la résolution mathématique de telles équations, regardez cette page.
Génération d’un programme en Python sous Cursor
C’est grâce à Korben que j’ai eu l’info: cursor est un logiciel qui permet de coder à l’aide de l’IA. J’ai donc voulu voir ce que cela donne. Le résultat en vidéo:
Le programme est le suivant:
import cmath def solve_quadratic(a, b, c): # Calculate the discriminant discriminant = cmath.sqrt(b**2 - 4*a*c) # Find two solutions sol1 = (-b - discriminant) / (2 * a) sol2 = (-b + discriminant) / (2 * a) return (sol1, sol2) if __name__ == "__main__": a = float(input("Enter the coefficient of x^2 (a): ")) b = float(input("Enter the coefficient of x (b): ")) c = float(input("Enter the constant term (c): ")) solutions = solve_quadratic(a, b, c) print("The solutions are {0} and {1}".format(solutions[0], solutions[1]))
À deux poils de cul près, ça ressemble à celui proposé par chatGPT. En fait, c’est pire car j’avais bien demandé de résoudre sur l’ensemble des réels, mais il m’a fait ça sur l’ensemble des nombres complexes cet abruti! Et en anglais en plus ! Pfiou !
N’empêche que ça e me va pas du tout ! Je n’ai toujours pas de valeurs exactes!
Rien ne vaut le travail fait la main (et au cerveau) !
Mon propre programme
Avant de se lancer dans le script, il faut analyser les situations délicates.
Lorsque le discriminant n’est pas un carré parfait, les solutions (quand elles existent) ne sont pas rationnelles. Et même quand le discriminant est un carré parfait, on peut se retrouver avec une solution rationnelle non décimale (par exemple, \(\frac{1}{3}\) qui va s’écrire 0.3333333333333… Beurk!
Il y a donc deux problématiques:
- simplifier les racines quand il y a des fractions
- simplifier la racine carrée du discriminant
Pour simplifier les fractions, on peut utiliser le module fractions.
En revanche, pour simplifier la racine carrée du discriminant, il n’y a pas de module à ma connaissance. Il faut donc bidouiller un script… Et ce n’est pas si difficile que ça: on décompose le discriminant en produit de facteurs premiers, que l’on utilise pour simplifier la racine carrée.
Ça donne un programme assez volumineux (86 lignes de code) mais il faut ce qu’il faut!
from fractions import Fraction """ Décomposition en produit de facteurs premiers: retourne un dictionnaire de la forme { (p1:exp1), ... } """ def decomp(n): D = dict() # dictionnaire vide k = 2 while n > 1: exposant = 0 while n%k == 0: exposant = exposant + 1 n = n/k if exposant != 0: D[k] = exposant k = k+1 j = 2 while k%j == 0: k = k + 1 return D """ Simplification d'une racine carrée """ def simp(x): x = Fraction(x) numer = decomp(x.numerator) denom = decomp(x.denominator) coef_num, radicand_num = 1, 1 for facteur, exposant in numer.items(): coef_num *= facteur**(exposant//2) if exposant%2 == 1: radicand_num *= facteur coef_denom, radicand_denom = 1, 1 for facteur, exposant in denom.items(): coef_denom *= facteur**(exposant//2) if exposant%2 == 1: radicand_denom *= facteur return Fraction(coef_num,coef_denom), Fraction(radicand_num,radicand_denom) """ Trouve les éventuelles racines d'un trinôme de degré 2 """ def racines(*coefs): if len(coefs) != 3: return 'Erreur dans la saisie des coefficients.' else: a, b, c = coefs[0], coefs[1], coefs[2] delta = b*b - 4*a*c if delta < 0: r = f'Δ = {delta} < 0 donc le trinôme d\'admet aucune racine.' elif delta == 0: r = f'Δ = 0 donc le trinôme admet une racine: {Fraction(-b,2*a)}.' else: coef, radicand = simp(delta) # sous la forme: coef, radicand if radicand == 1: x1, x2 = Fraction(-b-int(delta**0.5),2*a), Fraction(-b+int(delta**0.5),2*a) r = f'Δ = {delta} > 0 donc le trinôme admet deux racines: x₁ = {x1} et x₂ = {x2}.' else: c = abs(Fraction(coef,2*a)) if c.numerator == 1: if c.denominator == 1: r = f'Δ = {delta} > 0 donc le trinôme admet deux racines:\n \ x₁ = {Fraction(-b,2*a)} + √({radicand}) et \ x₂ = {Fraction(-b,2*a)} - √({radicand}).' else: r = f'Δ = {delta} > 0 donc le trinôme admet deux racines:\n \ x₁ = {Fraction(-b,2*a)} + √({radicand})/{c.denominator} et \ x₂ = {Fraction(-b,2*a)} - √({radicand})/{c.denominator}.' else: if c.denominator == 1: r = f'Δ = {delta} > 0 donc le trinôme admet deux racines:\n \ x₁ = {Fraction(-b,2*a)} + {c.numerator}√({radicand}) et \ x₂ = {Fraction(-b,2*a)} - {c.numerator}√({radicand}).' else: r = f'Δ = {delta} > 0 donc le trinôme admet deux racines:\n \ x₁ = {Fraction(-b,2*a)} + ({c.numerator}/{c.denominator})√({radicand}) et \ x₂ = {Fraction(-b,2*a)} - ({c.numerator}/{c.denominator})√({radicand}).' return r
Voici quelques exemples de ce qu’il donne:
Pour trouver les racines réelles de \(\frac{1}{4}x^2+\frac{1}{3}x-\frac{1}{5}\):
>>> print( racines(Fraction(1,4),Fraction(1,3),-Fraction(1,5)) )
Δ = 14/45 > 0 donc le trinôme admet deux racines:
x₁ = -2/3 + (2/3)√(14/5) et x₂ = -2/3 - (2/3)√(14/5).
Si le polynôme est \(x^2+x-1\), cela donne:
>>> print( racines(1,1,-1) )
Δ = 5 > 0 donc le trinôme admet deux racines:
x₁ = -1/2 + √(5)/2 et x₂ = -1/2 - √(5)/2.
Avec \(x^2-5x+4\):
>>> print( racines(1,-5,4) )
Δ = 9 > 0 donc le trinôme admet deux racines: x₁ = 1 et x₂ = 4.
Pour le moment, je n’ai pas implémenté de solution avec des coefficients radicaux, mais c’est assez simple au final. Il suffit en effet d’implémenter une classe Sqrt.
Je complèterai cet article quand je l’aurai fait très prochainement.
Avec la requête “écrit un programme python en utilisant simpy qui résout toute équation du second degré.” j’obtient de ChatGTP le programme :
que je teste avec :
Ce qui donne à l’exécution :
Je continue avec : “complète le programme suivant pour qu’il écrive un fichier Latex présentant l’équation et ses solutions : ‘import sympy as sp […]'”
ChatGPT complète avec :
Le fichier “equation_et_solutions.tex” créé par le programme :
et ci-joint une image du résultat compilé.
ChatGPT est tout de même extrêmement efficace et rapide pour obtenir un résultat satisfaisant.
Très intéressant! Je n’avais même pas pensé à passer par Simpy, même de façon manuelle, et encore moins à la partie \(\LaTeX\)., qui s’adresse tout de même à un public averti. Cet article a été écrit suite à un cours sur le second degré (par anticipation du programme de 1ère) que j’ai donné récemment à un élève de Seconde qui passe en 1ère et qui a un très bon niveau. Comme il aime coder en Python, je lui ai demandé d’écrire un programme qui trouve les racines (réelles) d’un trinôme de degré 2, et c’est dans cette logique que j’ai écrit ce article donc. Je n’ai pas pris de recul, et cette solution avec Simpy est quand-même bien meilleure.
Je ne manipule presque jamais Simpy et je vois qu’il offre pas mal d’opportunités, y compris pour la liaison avec \(\LaTeX\).
Ce commentaire est important pour souligner qu’avec ChatGPT, il faut être extrêmement précis sur nos intentions pour qu’il offre un résultat convenable.C’est pour cela qu’il m’a proposé un script basique au début: car ma requête l’était tout autant.Il est vrai que je n’utilise pas beaucoup ChatGPT et je retiens donc cette logique. Merci.