#!/usr/bin/python3
# -*- coding: utf-8 -*-

import math


class cuadratica:
    """
    Resuelve una ecuacion cuadratica.

    Encuentra las dos raices que resuelven la ecuacion cuadratica:

            ax^2 + bx + c = 0.

    Utiliza la formula general (tambien conocida
    coloquialmente como el "chicharronera 1 y 2")
    y el metodo de Newton-Rapson.

    Parametros:
    a -- coeficiente cuadratico (debe ser distinto de 0)
    b -- coeficiente lineal
    c -- termino independiente

    Error:
    Si (a == 0)

    """

    def __init__(self, a, b, c):
        """Constuctor"""
        if a == 0:
            print("No es una ecuacion cuadratica")
            exit(1)
        self.A = a
        self.B = b
        self.C = c

    def f(self, x):
        """Evalua la Funcion cuadratica"""
        return x * x * self.A + x * self.B + self.C

    def df(self, x):
        """Evalua la derivada de la funcion cuadratica"""
        return 2.0 * x * self.A + self.B

    def evalua(self, x):
        """Evalua el valor X en la función cuadratica"""
        print("Raiz (%1.16f), evaluacion raiz: %1.16e" % (x, self.f(x)))

    def metodoNewtonRapson(self, x, ni):
        """Metodo Newton-Raphson x = x - f(x)/f'(x)"""
        for i in range(ni):
            x = x - (self.f(x) / self.df(x))
        return x

    def raices(self):
        """Calculo de raices"""
        # Calculo del discriminante
        d = self.B * self.B - 4.0 * self.A * self.C

        # Raices reales
        if d >= 0.0:
            print(
                "\nPolinomio (%f) X^2 + (%f )X + (%f) = 0\n" % (self.A, self.B, self.C)
            )
            print("\nChicharronera 1")
            X1 = (-self.B + math.sqrt(d)) / (2.0 * self.A)
            X2 = (-self.B - math.sqrt(d)) / (2.0 * self.A)
            self.evalua(X1)
            self.evalua(X2)
            print("\nChicharronera 2")
            X1 = (-2.0 * self.C) / (self.B + math.sqrt(d))
            X2 = (-2.0 * self.C) / (self.B - math.sqrt(d))
            self.evalua(X1)
            self.evalua(X2)

            # Metodo Newton-Raphson
            print("\n\nMetodo Newton-Raphson")
            x = X1 - 1.0
            print("\nValor inicial aproximado de X1 =  %1.16f" % x)
            x = self.metodoNewtonRapson(x, 6)
            self.evalua(x)
            x = X2 - 1.0
            print("\nValor inicial aproximado de X2 =  %1.16f" % x)
            x = self.metodoNewtonRapson(x, 6)
            self.evalua(x)
            print("\n")
        else:
            # Raices complejas
            print("Raices Complejas ...")


if __name__ == "__main__":
    ej1 = cuadratica(1.0, 4.0, 1.0)
    ej1.raices()

    ej2 = cuadratica(-2, 4.0, 1.0)
    ej2.raices()

    ej3 = cuadratica(1.0, 2.0, 2.0)
    ej3.raices()

    print("prueba de convergencia")
    print(ej1.metodoNewtonRapson(100.0, 10))
    print(ej1.metodoNewtonRapson(100000.0, 20))
