""" ax2bxc.py
"""
#! /usr/bin/python3
# -*- coding: utf-8 -*-

# Résoudre une équation du second degré : a x² + b x + c = 0
# première version : la plus simple
def ax2bxc( a, b, c ) :
    print(f"ax2bxc() : f(x) = {a} x² + ({b}) x + ({c}) = 0")
    delta = b * b - 4 * a * c
    if delta < 0 :
        print("  0 solution dans R")
        racines = []
    elif delta == 0 :
        x1 = -b/(2*a)
        print(f"  1 solution : x1={x1}")
        racines = [-b/(2*a)]
    else :
        x1 = (-b - pow(delta, 0.5)) / (2*a)
        x2 = (-b + pow(delta, 0.5)) / (2*a)
        print(f"  2 solutions : x1={x1}, x2={x2}")
        racines = [ x1, x2 ]
    # contrôle des résultats :
    for x in racines :
        verification_racine( a, b, c, x )
    return racines

def verification_racine( a, b, c, x ) :
    resultat = a * x*x + b * x + c
    if abs(resultat) > 1.e-9 :
        print(f"  verification_racine() : f({x})=", resultat, "> 1.e-9 pb")
    else :
        print(f"  verification_racine() : f({x})=", resultat, "< 1.e-9 ok")
    return 

def ax2bxc_test() :
    print("""### test des 3 cas possibles de la fonction ax2bxc() ###
    x^2 + 1 = 0     -> racines = []
    (x+1)^2 = 0     -> racines = [-1]
    (x-2)(x-3) = 0  -> racines = [2, 3]
    Comparaison des fonctions ax2bxc() et ax2bxc_amelioree()
    """)
    liste_tests = [ ( 1, 0, 1, [] ),
                    ( 1, 2, 1, [-1] ),
                    ( 1, -5, 6, [2, 3] )]
    for (a, b, c, solution) in liste_tests :
        racines = ax2bxc( a, b, c )
        if len(racines) != len(solution) :
            print(f"ERREUR : racines={racines} != sol={sol}")
    return

def ax2bxc_limite() :
    print("""
### limites de validité de la fonction ###
    2 racines : une petite x1=1 et une grande x2 > 1e10
    la précision des nombres réels est de l'ordre de 1e-16
    1 + 1e17 = 1e17 : le 1 est totalement perdu""")
    # (x-x1)(x-x2) = 0
    x1, x2 = (1, 1e17)
    a, b, c = (1, -(x1+x2), x1*x2)
    sol1 = ax2bxc(a, b, c)
    sol2 = ax2bxc_amelioree( a, b, c )
    print(f"""\nComparaison des résultats des 2 fonctions :
  ax2bxc()           solution={sol1} != (x1,x2)={(x1,x2)}
                     trouve la grande solution (en valeur absolue),
                     la petite est perdue.
  ax2bxc_amelioree() solution={sol2} == (x1,x2)={(x1,x2)}
                     trouve les 2 solutions""")
    return

def ax2bxc_amelioree( a, b, c ) :
    """ on calcule la plus grande racine (en valeur absolue)
    on en déduit la petite racine en utilisant le produit des racines = c/a
    car -b + sqrt(delta) est peu précis quand a*c est petit devant b²
     sqrt(delta) = |b| sqrt(1-4ac/b²) ~ |b| (1 - (1/2)4ac/b² + ...)
     (1/2)4ac/b² est perdu dans les décimales de 1
    """
    print(f"ax2bxc_amelioree() : f(x) = {a} x² + ({b}) x + ({c}) = 0")
    delta = b * b - 4 * a * c
    if delta < 0 :
        print("  0 solution dans R")
        racines = []
    elif delta == 0 :
        x1 = -b/(2*a)
        print(f"  1 solution : x1={x1}")
        racines = [-b/(2*a)]
    else :
        # calcul de la grande racine |x2|
        # il faut additionner des nombres de mêmes signes
        if b < 0 :
            x2 = (-b + pow(delta, 0.5)) / (2*a)
        else :
            x2 = (-b - pow(delta, 0.5)) / (2*a)
        x1 = (c/a) / x2
        print(f"  2 solutions : x1={x1}, x2={x2}")
        racines = [ x1, x2 ]
    # contrôle des résultats :
    for x in racines :
        verification_racine( a, b, c, x )
    return racines

def ax2bxc_interactif() :
    print("""-> Entrez les 3 coefficients un par un """)
    a = "?"
    while a != "" :
        a = input("a (entrée vide pour terminer) ? ")
        if a == "" :
            break
        else :
            a = float(a)
        b = float(input("b ? "))
        c = float(input("c ? "))
        racines = ax2bxc_amelioree( a, b, c )
    
if __name__ == "__main__" :
    # début du programme :
    ax2bxc_test()
    ax2bxc_limite()
    print("""\n### à vous maintenant de résoudre a x² + b x + c = 0 ###""")
    ax2bxc_interactif()

"""
"""