Repository: TheAlgorithms/C-Plus-Plus
File: math/quadratic_equations_complex_numbers.cpp (C++)

Code before:
/**
 * @file
 * @brief Calculate quadratic equation with complex roots, i.e. b^2 - 4ac < 0.
 * @see https://en.wikipedia.org/wiki/Quadratic_equation,
 * https://en.wikipedia.org/wiki/Quadratic_equation#discriminant
 *
 * @author [Renjian-buchai](https://github.com/Renjian-buchai)
 */

#include <array>
#include <cassert>
#include <cmath>
#include <complex>
#include <exception>
#include <iomanip>
#include <iostream>

/// @brief Quadratic equation calculator.
/// @param a quadratic coefficient.
/// @param b linear coefficient.
/// @param c constant
/// @return Array containing the roots of quadratic equation, incl. complex
/// root.
std::array<std::complex<long double>, 2> quadraticEquation(long double a,
                                                           long double b,
                                                           long double c) {
    /**
     * Calculates any quadratic equation in form ax^2 + bx + c.
     *
     * Quadratic equation:
     * x = (-b +/- sqrt(b^2 - 4ac)) / 2a
     *
     * e.g.
     * using namespace std;
     * int main() {
     *   array<complex<long double, 2> solutions = quadraticEquation(1, 2, 1);
     *   cout << solutions[0] << " " << solutions[1] << "\n";
     *
     *   solutions = quadraticEquation(1, 1, 1);  // Reusing solutions.
     *   cout << solutions[0] << " " << solutions[1] << "\n";
     *   return 0;
     * }
     *
     * Output:
     * (-1, 0) (-1, 0)
     * (-0.5,0.866025) (-0.5,0.866025)
     */

    if (a == 0)
        throw std::invalid_argument("quadratic coefficient cannot be 0");

    long double discriminant = b * b - 4 * a * c;
    std::array<std::complex<long double>, 2> solutions{0, 0};

    /// Complex root (discriminant < 0)
    /// Note that the left term (-b / 2a) is always real. The imaginary part
    /// appears when b^2 - 4ac < 0, so sqrt(b^2 - 4ac) has no real roots. So,
    /// the imaginary component is i * (+/-)sqrt(abs(b^2 - 4ac)) / 2a.
    if (discriminant < 0) {
        /// Since b^2 - 4ac is < 0, for faster computation, -discriminant is
        /// enough to make it positive.
        solutions[0] = std::complex<long double>{
            -b * 0.5 / a, -std::sqrt(-discriminant) * 0.5 / a};
        solutions[1] = std::complex<long double>{
            -b * 0.5 / a, std::sqrt(-discriminant) * 0.5 / a};
    } else {
        /// Since discriminant > 0, there are only real roots. Therefore,
        /// imaginary component = 0.
        solutions[0] = std::complex<long double>{
            (-b - std::sqrt(discriminant)) * 0.5 / a, 0};
        solutions[1] = std::complex<long double>{
            (-b + std::sqrt(discriminant)) * 0.5 / a, 0};
    }

    return solutions;
}

static void test() {
    std::array<std::complex<long double>, 2> realCase{
        std::complex<long double>{1, 0}, std::complex<long double>{1, 0}};
    assert(quadraticEquation(1, -2, 1) == realCase);

    std::array<std::complex<long double>, 2> complexCase{
        std::complex<long double>{-2, -1}, std::complex<long double>{-2, 1}};
    assert(quadraticEquation(1, 4, 5) == complexCase);

    return;
}

int main() {
    test();

    std::array<std::complex<long double>, 2> aaa = quadraticEquation(1, 1, 1);
    std::cout << "The complex roots of x^2 + x + 1 are " << aaa[0] << " and "
              << aaa[1]
              << ".\nMore precisely, and with the inaccuracy of floating point "
                 "numbers, "
              << std::setprecision(100) << aaa[0] << " and " << aaa[1] << "\n";

    return 0;
}


Review comment (suggestion):
```suggestion
/**
 * @brief Main function
 * @returns 0 on exit
 */
```

Code after:
        std::complex<long double>{1, 0}, std::complex<long double>{1, 0}};
    assert(math::quadraticEquation(1, -2, 1) == equalCase);

    // Values are equal and complex.
    std::cout << "Input: \n"
                 "a=1 \n"
                 "b=4 \n"
                 "c=5 \n"
                 "Expected output: \n"
                 "(-2, -1), (-2, 1)\n\n";
    std::array<std::complex<long double>, 2> complexCase{
        std::complex<long double>{-2, -1}, std::complex<long double>{-2, 1}};
    assert(math::quadraticEquation(1, 4, 5) == complexCase);

    // Values are real.
    std::cout << "Input: \n"
                 "a=1 \n"
                 "b=5 \n"
                 "c=1 \n"
                 "Expected output: \n"
                 "(-4.7912878475, 0), (-0.2087121525, 0)\n\n";
    std::array<std::complex<long double>, 2> floatCase{
        std::complex<long double>{-4.7912878475, 0},
        std::complex<long double>{-0.2087121525, 0}};
    assertArray(math::quadraticEquation(1, 5, 1), floatCase);

    // Values are complex.
    std::cout << "Input: \n"
                 "a=1 \n"
                 "b=1 \n"
                 "c=1 \n"
                 "Expected output: \n"
                 "(-0.5, -0.8660254038), (-0.5, 0.8660254038)\n\n";
    std::array<std::complex<long double>, 2> ifloatCase{
        std::complex<long double>{-0.5, -0.8660254038},
        std::complex<long double>{-0.5, 0.8660254038}};
    assertArray(math::quadraticEquation(1, 1, 1), ifloatCase);

    std::cout << "Exception test: \n"
                 "Input: \n"
                 "a=0 \n"
                 "b=0 \n"
                 "c=0\n"
                 "Expected output: Exception thrown \n";
    try {
        math::quadraticEquation(0, 0, 0);
    } catch (std::invalid_argument& e) {
        std::cout << "Exception thrown successfully \n";
    }
}