#include <iostream>
#include <cmath>
#include <iomanip>

// Constanta PI portabila (M_PI nu e standard C++)
const double PI = std::acos(-1.0);
const double EPS = 1e-12;

/**
 * Rezolva ecuatia de gradul 3: a*x^3 + b*x^2 + c*x + d = 0
 * Metoda: Cardano (formula trigonometrica pentru Δ < 0)
 */
void rezolvaEcuatieGrad3(double a, double b, double c, double d) {
    if (std::abs(a) < EPS) {
        std::cout << "Nu este ecuatie de gradul 3!" << std::endl;
        return;
    }

    // Coeficientii redusi (substitutia x = y - b/(3a))
    double p = (3.0 * a * c - b * b) / (3.0 * a * a);
    double q = (2.0 * b * b * b - 9.0 * a * b * c
                + 27.0 * a * a * d) / (27.0 * a * a * a);
    double delta = (q * q / 4.0) + (p * p * p / 27.0);

    std::cout << "p = " << p << ", q = " << q << std::endl;
    std::cout << "Discriminant = " << delta << std::endl;

    double offset = -b / (3.0 * a);

    // Epsilon pentru comparatii floating-point
    if (delta > EPS) {
        // O radacina reala, doua complexe
        double u = std::cbrt(-q / 2.0 + std::sqrt(delta));
        double v = std::cbrt(-q / 2.0 - std::sqrt(delta));
        double x1 = u + v + offset;
        double re = -0.5 * (u + v) + offset;
        double im = std::sqrt(3.0) / 2.0 * (u - v);

        // Normalizeaza -0.0 la 0.0
        if (std::abs(im) < EPS) im = 0.0;

        std::cout << "x1 = " << x1 << std::endl;
        std::cout << "x2 = " << re << " + " << im << "i" << std::endl;
        std::cout << "x3 = " << re << " - " << im << "i" << std::endl;

    } else if (std::abs(delta) <= EPS) {
        // Cel putin doua radacini reale egale
        if (std::abs(p) < EPS && std::abs(q) < EPS) {
            // Caz special: radacina tripla
            double x = offset;
            if (std::abs(x) < EPS) x = 0.0;
            std::cout << "x1 = x2 = x3 = " << x << " (radacina tripla)" << std::endl;
        } else {
            double u = std::cbrt(-q / 2.0);
            double x_dublu = -u + offset;   // radacina dubla
            double x_simplu = 2.0 * u + offset; // radacina simpla
            if (std::abs(x_dublu) < EPS) x_dublu = 0.0;
            if (std::abs(x_simplu) < EPS) x_simplu = 0.0;
            std::cout << "x1 = x2 = " << x_dublu << " (radacina dubla)" << std::endl;
            std::cout << "x3 = " << x_simplu << std::endl;
        }

    } else {
        // Trei radacini reale distincte (cazul trigonometric)
        double r = std::sqrt(-p * p * p / 27.0);
        double arg = -q / (2.0 * r);

        // Clampeaza argumentul in [-1, 1] pentru acos (stabilitate numerica)
        if (arg > 1.0) arg = 1.0;
        if (arg < -1.0) arg = -1.0;

        double theta = std::acos(arg);
        for (int i = 0; i < 3; i++) {
            double x = 2.0 * std::cbrt(r)
                     * std::cos((theta + 2.0 * PI * i) / 3.0) + offset;
            if (std::abs(x) < EPS) x = 0.0;
            std::cout << "x" << (i + 1) << " = " << x << std::endl;
        }
    }
}

int main() {
    double a, b, c, d;
    std::cout << "Introdu coeficientii a, b, c, d: ";
    std::cin >> a >> b >> c >> d;

    std::cout << "Ecuatia: " << a << "x^3 + " << b
              << "x^2 + " << c << "x + " << d << " = 0" << std::endl;
    std::cout << "Solutiile:" << std::endl;
    rezolvaEcuatieGrad3(a, b, c, d);

    return 0;
}
