Using The Complex Type to Solve Quadratic Equations

Introduction

One of the more interesting types introduced in .NET Framework 4.0 is the Complex structure which models the mathematical entity known as a 'complex number'. This is a number of the form a + bi where I represent the square root of -1.

The Complex structure lives in the System.Numerics namespace and, to use it, you need to add a reference to System.Numerics.dll to your project.

The implementation is reasonably complete with the standard arithmetic operators (+, -, *, /) being overloaded to work with complex numbers and there are implicit conversions from all the standard arithmetic types (int, long, double, etc.). Construction using polar coordinates is supported and there is also a full set of mathematical functions defined on complex numbers such as trigonometric, absolute value, conjugate, reciprocal, power, and square root.

So how can we use this type to solve a quadratic equation?

Solving quadratic equations (a first attempt)

One of the reasons why complex numbers were introduced into mathematics in the first place is so that the quadratic equation.

ax^2 + bx + c = 0 // where a, b, and c are real numbers, a is non-zero, and ^ denotes the power function.

always has a solution and, indeed, exactly two solutions or roots as they are called. For example, the equation.

x^2 + 4 = 0

has no real roots but it does have the complex roots 2i and -2i.

In general, the roots of any quadratic equation can be found in the formulas.

(-b + Sqrt (b^2- 4ac))/ 2a and (-b - Sqrt (b^2 - 4ac))/ 2a

It can be seen from these formulas that if b^2 - 4ac (known as the discriminant) is negative then the roots will be complex rather than real numbers.

So, on the face of it, we should be able to solve such equations with the following C# program.

using System;
using System.Numerics;

class Test
{
    static void Main()
    {
        // as an example let's solve x^2 + 4 = 0
        Tuple<Complex, Complex> roots = SolveQuadratic(1, 0, 4);
        Console.WriteLine("The roots are {0} and {1}", roots.Item1, roots.Item2);
        Console.ReadKey();
    }

    static Tuple<Complex, Complex> SolveQuadratic(double a, double b, double c)
    {
        if (a == 0) throw new ArgumentException("The coefficient of x squared can't be zero");
        double discriminant = b * b - 4.0 * a * c;
        Complex temp = Complex.Sqrt(discriminant);
        Complex root1 = (-b + temp) / (2.0 * a);
        Complex root2 = (-b - temp) / (2.0 * a);
        return Tuple.Create(root1, root2);
    }
}

Notice that we're using the generic Tuple class which is another new feature of .NET 4.0. This enables us to return multiple values from a method without the need for 'out' parameters or defining a custom type.

However, when we examine the output of this program, we see two problems.

The roots are (1.22460635382238E-16, 2) and (-1.22460635382238E-16, -2).

Firstly, the roots have a tiny real component and secondly, the output is expressed in Cartesian form (like points on the plane) and not in the more familiar a + bi format.

So what can we do about these problems?

Solving quadratic equations (an improved version)

Clearly, the first problem is caused by the Complex. Sqrt method producing anomalous results. The obvious way to solve this is to use the Math. Sqrt method instead and, if the discriminant is negative, multiply the result by the square root of -1.

As far as I can see, there is no support for the a + bi format in the Complex.ToString method or anywhere else so we need to write a custom method to deal with this. This gives us the following improved version of the program.

using System;
using System.Numerics;

class Test
{
    static void Main()
    {
        // as an example let's solve x^2 + 4 = 0
        Tuple<Complex, Complex> roots = SolveQuadratic(1, 0, 4);
        Console.WriteLine("The roots are {0} and {1}", ShowComplex(roots.Item1), ShowComplex(roots.Item2));

        // and also x^2 - 2x + 2
        roots = SolveQuadratic(1, -2, 2);
        Console.WriteLine("The roots are {0} and {1}", ShowComplex(roots.Item1), ShowComplex(roots.Item2));
        Console.ReadKey();
    }

    static Tuple<Complex, Complex> SolveQuadratic(double a, double b, double c)
    {
        if (a == 0) throw new ArgumentException("The coefficient of x squared can't be zero");
        double discriminant = b * b - 4.0 * a * c;
        Complex temp;
        if (discriminant >= 0)
        {
            temp = new Complex(Math.Sqrt(discriminant), 0);
        }
        else
        {
            temp = new Complex(0, Math.Sqrt(-discriminant));
        }
        Complex root1 = (-b + temp) / (2.0 * a);
        Complex root2 = (-b - temp) / (2.0 * a);
        return Tuple.Create(root1, root2);
    }

    static string ShowComplex(Complex c)
    {
        if (c == Complex.Zero) return "0";
        if (c.Imaginary == 0.0) return c.Real.ToString();
        string imag;
        if (c.Imaginary == 1)
            imag = "i";
        else if (c.Imaginary == -1)
            imag = "-i";
        else
            imag = c.Imaginary.ToString() + "i";
        if (c.Real == 0.0) return imag;
        string sep = (c.Imaginary > 0.0) ? "+" : "";
        return c.Real.ToString() + sep + imag;
    }
}

The output is now as expected.

  • The roots are 2i and -2i
  • The roots are 1+i and 1-i


Similar Articles