Complex Numbers in .Net (C#)

I'll soon be posting up some code related to the generation of the mandelbrot set in c#. Here I'll lay the groundwork for that by describing what complex numbers are and how we can deal with them in C#.

Complex Numbers

Notice that 2 * (-2) = -4 but there is no 'real' number that can be multiplied by itself in order to give the required answer, -4. For this, we introduce the concept of the imaginary number. Mathematicians give a name to square root of -1. They call it i. By definition, if we square i we get -1. If we raise it to the third power, we get -i, and if we raise it the fourth power, we're essentially squaring -1, so we get 1. i can be multiplied and added to numbers in the real set so 4 * i = 4i and 3i + 2i = 5i. However, 3 + 2i cannot be simplified any further; it is just 3 + 2i, and this is in fact a complex number. A complex number is a number that consists of two parts; a real part and an imaginary part. The common operations of addition, subtraction, multiplication and division work a little bit differently with complex numbers. In order to use complex numbers in any object oriented language, we can build a class that stores these two parts and overrides the mathematical operators so we can add and multiply our complex number objects. Very intuitive stuff!

Evolution of Number

The first numbers humans were able to make sense of were the 'natural' numbers; 1,2,3 etc. The concept of 'zero' hasn't always existed in mathematics and seems to have been rediscovered and forgotten several times before we finally accepted it as something that helps us accurately describe our reality. Negative numbers were introduced to allow us to solve problems that we couldn't solve previously. They helped us understand the concept of debt and allowed us to solve new types of equations. At first, the concept of negative numbers was probably very alien but they've proven themselves as in invaluable tool to allow us to better understand the world around us. Rational numbers such as 2/3 were introduced and numbers like pi and e were discovered, leading us to deal with the concept of irrational numbers; numbers that cannot be expressed as a fraction consisting of integers but instead are described by an infinite string of digits. OK, imaginary numbers. This is where things get a little strange, but it's important to remember that the numbers discussed next have real mathematical implications. They are of great importance in science and engineering and the fact that we call them 'imaginary numbers' does not mean they're just a useless mathematical invention. Imaginary numbers come about because we need a mechanism that will allow us to deal with square roots of negative numbers. The Square of a number is the value you get when you multiply the number by itself. The square of 2 (or 2 squared) is 4 because 2 * 2 = 4. The square root of a number is the number that you multiply by itself to get to the original number, so the square root of 9 is 3 because 3 * 3 = 9. We know that 2 * 2 = 4 and we also know that (-2) * (-2) = 4, because a negative multiplied by a negative produces a positive. So, 2 and -2 are the two answers to the question "what is the square root of 4?". But what if we want to ask the question "what is the square root of -4?"

C# Class for Complex Numbers

namespace ComplexNumbers
{
    class Complex
    {
        private Double _r;
        private Double _i;

        public Double R
        {
            get { return _r; }
            set { _r = value; }
        }

        public Double I
        {
            get { return _i; }
            set { _i = value; }
        }

        public Complex(Double real, Double imaginary)
        {
            _r = real;
            _i = imaginary;
        }

        public static Complex operator +(Complex c1, Complex c2)
        {
            Double r = c1.R + c2.R;
            Double i = c1.I + c2.I;

            return new Complex(r, i);
        }

        public static Complex operator -(Complex c1, Complex c2)
        {
            Double r = c1.R - c2.R;
            Double i = c1.I - c2.I;

            return new Complex(r, i);
        }

        public static Complex operator *(Complex c1, Complex c2)
        {
            Double r = c1.R * c2.R - c1.I * c2.I;
            Double i = c1.R * c2.I + c2.R * c1.I;

            return new Complex(r, i);
        }

        public static Complex operator /(Complex c1, Complex c2)
        {
            Complex tmp = new Complex(c2.R, -c2.I);
            c1 *= tmp;
            c2 *= tmp;

            if (c2 == 0)
                throw new DivideByZeroException();

            return (c1 * (1 / c2.R));
        }

        public static Boolean operator ==(Complex c1, Complex c2)
        {
            return (c1.R == c2.R && c1.I == c2.I);
        }

        public static Boolean operator !=(Complex c1, Complex c2)
        {
            return !(c1.R == c2.R && c1.I == c2.I);
        }

        public override int GetHashCode()
        {
            return R.GetHashCode() ^ I.GetHashCode();
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            if (R != 0)
                sb.Append(R.ToString());

            if (R != 0 && I > 0)
                sb.Append(" + ");

            if (I < 0)
            {
                if (R != 0)
                    sb.Append(" ");
                sb.Append("-");
                if (R != 0)
                    sb.Append(" "); 
            }

            if (R == 0 && I == 0)
                sb.Append("0");

            if (I != 0)
            {
                if (Math.Abs(I) != 1)
                    sb.Append(Math.Abs(I).ToString());
                sb.Append("i");
            }

            return sb.ToString();
        }

        public static implicit operator Complex(Double n)
        {
            return new Complex(n, 0);
        }

    }
}

Addition and subtraction operators are simple. We simply add or subtract the two separate components of each complex number. Multiplication is a little more complicated. Each part has two components so we need to cross multiply using the FOIL method. Multiply two complex together and you'll see why it can be written in the way I've done it above. The division code might look a little strange but I'm basically rationalising the denominator to get rid of the imaginary term. An excellent description of how to multiply and divide complex numbers can be found here. Notice that I've defined an implicit cast operator so we can do nice things like the following.


Complex c = new Complex(-2, 1.6);

Complex z = c + 5.2;

In this example, the 5 is implicity casted up to a complex type that has real part 5 and imaginary part 0. Also, implicit casting means that we don't need to overload each operator 3 times to deal with, say, adding a float to a Complex or a Complex to a float. In my next post, I'll be using this class to produce an animation of the mandelbrot set.

Comments

No comments yet.

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article
    working