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

import math


"""
	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 f(x, a, b, c):
    """Evalua la Funcion cuadratica"""
    return x * x * a + x * b + c


def df(x, a, b):
    """Evalua la derivada de la funcion cuadratica"""
    return 2.0 * x * a + b


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


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


def raices(A, B, C):
    """Calculo de raices"""

    if A == 0.0:
        print("No es una ecuacion cuadratica")
        exit(1)
    # Calculo del discriminante
    d = B * B - 4.0 * A * C

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

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


if __name__ == "__main__":
    raices(1.0, 4.0, 1.0)
    raices(-2.0, 4.0, 1.0)
    raices(1.0, 2.0, 3.0)
    
    print("Pruba de Convergencia")
    print(metodoNewtonRapson(100.0, 10, 1.0, 4.0, 1.0))
    print(metodoNewtonRapson(100000.0, 20, 1.0, 4.0, 1.0))
