#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

double calcul(double poly5[], double x) // on crée une fonction pour éviter la répétition des calculs dans le main
{
    double result;
    result = poly5[0] * (x * x * x * x * x) + poly5[1] * (x * x * x * x) + poly5[2] * (x * x * x) + poly5[3] * (x * x) + poly5[4] * x + poly5[5];
    return result;
}

int main()
{
    double val1, val2, val3, val4, temp, R, racine_delta, delta, u, z;
    double poly5[6]; //tableau qui contiendra tous les coefficients du polynome de degré 5
    int i;

    cout << "saisir a b c d e et f" << endl;

    /*                           /
    /  saisie des coefficients   /
    /                           */

    for(i = 0; i < 6; i++)
    {
    cin >> poly5[i];
    }

    // on attribue les intervalles de départ, entre -1 et 1, val1 sera le plus à gauche et val4 le plus à droite;
    val2 = 0;
    val3 = val2;
    val1 = val2 - 1;
    val4 = val3 + 1;

    double res1, res2, res3, res4;
    //on fais le cacul pour chaque valeurs précedemment choisi
    res1 = calcul(poly5,val1);
    res2 = calcul(poly5,val2);
    res3 = calcul(poly5,val3);
    res4 = calcul(poly5,val4);

    cout << val2 << endl;

    /*             /
    /  Dichotomie  /
    /             */

    for(i = 0; i < 24; i++)
    {
        if(res1 * res2 < 0) //si on trouve un changement de signe sur l'intervalle de gauche
        {
            temp = val2;
            val2 = ((val1 + temp) / 2.0); //val2 se replace au centre de val1-val2
            val3 = val2; //val3 se place sur val2
            val4 = temp; //val4 reprend la place de val2, on a donc un intervalle réduit
        }
        else if(res3 * res4 < 0) //si il y a un changement de signe sur l'intervalle de droite
        {
            //on procède à la même étape que précedemment mais cette fois à droite (vers les valeurs positives)
            temp = val3;
            val3 = ((temp + val4) / 2.0);
            val2 = val3;
            val1 = temp;
        }
        cout << val2 << endl;
        while((res1 * res2 > 0) && (res3 * res4 > 0)) //si il n'y a pas de changement de signe
        {
            //on agrandit les deux intervalles sans recompter les valeurs déjà calculées
            val1 = val1 - (1 / pow(10,i));
            val2 = val2 - (1 / pow(10,i));
            val3 = val3 + (1 / pow(10,i));
            val4 = val4 + (1 / pow(10,i));

            //on recalcul
            res1 = calcul(poly5,val1);
            res2 = calcul(poly5,val2);
            res3 = calcul(poly5,val3);
            res4 = calcul(poly5,val4);
        }//boucle : on recommence tant qu'on trouve pas de changement de signe
        res1 = calcul(poly5,val1);
        res2 = calcul(poly5,val2);
        res3 = calcul(poly5,val3);
        res4 = calcul(poly5,val4);
    }//fin de la dichotomie

    /*             /
    /    Ferrari   /
    /             */

    double poly4[5]; //tableau contenant les coefficients du polynome de degré 4
    poly4[0] = poly5[0];

    //on simule la division du polynome de degré 5 par la racine trouvé
    for(i = 1; i < 5; i++)
    {
        poly4[i] = poly5[i] + (poly4[i-1]*val2); //on calcul les coefficients du polynome 4, et les stocke dans le tableau
    }

    cout << endl << "On obtient par dichotomie une racine reelle : " << val2 << endl << endl;

    //on transforme notre équation du 4e degré grace à la formule de Ferrari
    double A, B, C;
    A = -(3*poly4[1]*poly4[1])/(8*poly4[0]*poly4[0]) + poly4[2]/poly4[0]; //-3b^2/8a^2 + c/a
    B = ((poly4[1]/2)*(poly4[1]/2)*(poly4[1]/2))/(poly4[0]*poly4[0]*poly4[0])
        - (0.5*poly4[1]*poly4[2])/(poly4[0]*poly4[0]) + poly4[3]/poly4[0]; //(b/2)^3/a^3 - ½bc/a^2 + d/a
    C = -3*((poly4[1]/4*poly4[0])*(poly4[1]/4*poly4[0])*(poly4[1]/4*poly4[0])*(poly4[1]/4*poly4[0]))
        + (poly4[2]*((poly4[1]/4)*(poly4[1]/4)))/(poly4[0]*poly4[0]*poly4[0])
        - (0.25*poly4[1]*poly4[3])/(poly4[0]*poly4[0]) + poly4[4]/poly4[0]; //-3(b/4a)^4 + c(b/4)^2/a^3 - ¼bd/a^2 + e/a

    /*             /
    /    Cardan    /
    /             */

    //avec quelques calculs sur les variables on arrive à notre première équation du 3e degré
    double a, b, c, d;
    a = 1;
    b = -A;
    c = (-4*C);
    d = (4*A*C) - (B*B);

    //avec un changement de variable on obtient la deuxième équation du 3e degré
    double p, q;
    p = (c/a) - ((b*b)/(3*a*a));
    q = (2*b*b*b)/(27*a*a*a) + (d/(a*a*a)) - (b*c)/(3*a*a);

    cout << "p = "; printf("%.7f", p); cout << "    q = "; printf("%.7f", q); cout << endl << endl;

    delta = ((q*q)/4) + ((p*p*p)/27); //cacul du delta pour trouver la racine du polynome avec les inconnues p et q
    racine_delta = sqrt(delta);

    R = cbrt(((-q/2) + racine_delta)) + cbrt(((-q/2) - racine_delta)); //calcul de la racine
    cout << "on obtient la racine du polynome de 3e degre d inconnue p et q : "; printf("%.7f", R); cout << endl << endl;

    u = R - b/(3*a); //grace à la racine on peut revenir sur la première équation du 3e degré, on caulcul u

    z = B/(2*(u - A)); // avec z on va pouvoir calculer une équation du 2e degré
    cout << "u = "; printf("%.7f", u); cout << "    z = "; printf("%.7f", z); cout << endl << endl;

    /*                  /
    / Racines réelles  /
    /                  */

    //calcul des coefficients de la première équation du 2e degré (pour racines réelles) avant le changement de variable
    a = 1;
    b = -sqrt(u - A);
    c = (u/2) + (sqrt(u - A) * z);

    // dernier changement de variable
    temp = poly4[1]/(4*poly4[0]); //calcul de b/4a
    poly5[1] = (2 * temp) + b;  // cacul du coefficient b de la dernière équation du 2e degré
    poly5[2] = (temp*temp) + (b*temp) + c; //calcul du coefficient c

    //on obtient un equation du 2e degré

    delta = (poly5[1]*poly5[1]) - (4*poly5[0]*poly5[2]); //calcul du delta

    //on calcul les 2 racines réelles
    res1 = (-poly5[1] - (sqrt(delta)))/(2*a);
    res2 = (-poly5[1] + (sqrt(delta)))/(2*a);
    cout << "Les trois racines reelles du polynome sont : " << endl << val2 << endl << res1 << endl << res2 << endl << endl;

    /*                    /
    /  Racines complexes  /
    /                    */

    //calcul des coefficients de la première équation du 2e degré (pour racines complexes) avant le changement de variable
    a = 1;
    b = sqrt(u - A);
    c = (u/2) - (sqrt(u - A) * z);

    poly5[1] = (2 * temp) + b; // cacul du coefficient b de la dernière équation du 2e degré
    poly5[2] = (temp*temp) + (b*temp) + c; //calcul du coefficient c

    delta = (poly5[1]*poly5[1]) - (4*poly5[0]*poly5[2]); //calcul du delta

    //calcul des 2 racines complexes
    res1 = (-poly5[1])/(2*a);
    res2 = (sqrt(delta*-1))/(2*a);

    cout << "Les deux racines complexes du polynome sont : " << endl << res1
        << " + " << res2 << "i" << endl << res1 << " - " << res2 << "i" << endl;

    /*                          /
    /  fin du programme : C Bô  /
    /                          */
    system("pause");
    return 0;
}
