C# in Depth

Cover of C# in Depth
Order now (3rd edition)

A generic Complex type

Chapter 3: Parameterized typing with generics: 3.6.2

Created: 24/02/2008
Last updated: 24/02/2008

Thanks to Marc Gravell's work on generic operators the idea of a Complex<T> type is no longer the realm of fantasy. It's still a lot of work, however, which is why it's so lovely that Marc's gone to the trouble of implementing it for us... He stresses that this hasn't been unit tested yet, but here it is in all its glory. (It relies on MiscUtil for generic operator support, of course.)

using System;
using System.Collections.Generic;
using MiscUtil;

struct Complex<T> : IEquatable<Complex<T>> 
{
    private readonly T real, imaginary;
    
    public Complex(T real, T imaginary) 
    {
        this.real = real;
        this.imaginary = imaginary;
    }
    
    public T RelativeLength() 
    {
        return SquareLength(ref this);
    }
    
    public T Real { get { return real; } }
    
    public T Imaginary { get { return imaginary; } }

    public override string ToString() 
    {
        return string.Format("({0}, {1}i)", real, imaginary);
    }
    
    public override bool Equals(object obj) 
    {
        if (obj != null && obj is Complex<T>) 
        {
            Complex<T> other = (Complex<T>)obj;
            return Equals(ref thisref other);
        }
        return base.Equals(obj);
    }
    
    public bool Equals(Complex<T> other) 
    {
        return Equals(this, other);
    }
    
    private static bool Equals(ref Complex<T> x, ref Complex<T> y) 
    {
        return EqualityComparer<T>.Default.Equals(x.Real, y.Real)
            && EqualityComparer<T>.Default.Equals(x.Imaginary, y.Imaginary);
    }
    
    public static Complex<T> operator +(Complex<T> x, Complex<T> y) 
    {
        return new Complex<T>(
            Operator.Add(x.Real, y.Real),
            Operator.Add(x.Imaginary, y.Imaginary)
        );
    }
    
    public static Complex<T> operator +(Complex<T> x, T y) 
    {
        return new Complex<T>(
            Operator.Add(x.Real, y),
            x.Imaginary
        );
    }
    
    public static Complex<T> operator -(Complex<T> x, Complex<T> y) 
    {
        return new Complex<T>(
            Operator.Subtract(x.Real, y.Real),
            Operator.Subtract(x.Imaginary, y.Imaginary)
        );
    }
    
    public static Complex<T> operator -(Complex<T> x, T y) 
    {
        return new Complex<T>(
            Operator.Subtract(x.Real, y),
            x.Imaginary
        );
    }
    
    public static Complex<T> operator -(Complex<T> x) 
    {
        return new Complex<T>(
            Operator.Negate(x.Real),
            Operator.Negate(x.Imaginary)
        );
    }
    
    public static bool operator ==(Complex<T> x, Complex<T> y) 
    {
        return Equals(ref x, ref y);
    }
    
    public static bool operator !=(Complex<T> x, Complex<T> y) 
    {
        return !Equals(ref x, ref y);
    }
    
    public static Complex<T> operator *(Complex<T> x, Complex<T> y) 
    {
        return new Complex<T>(
            Operator.Subtract(
                Operator.Multiply(x.Real, y.Real),
                Operator.Multiply(y.Imaginary, y.Imaginary)
            ), Operator.Add(
                Operator.Multiply(x.Real, y.Imaginary),
                Operator.Multiply(x.Imaginary, y.Real)
            )
        );
    }
    
    public static Complex<T> operator *(Complex<T> x, T y) 
    {
        return new Complex<T>(
            Operator.Multiply(x.Real, y),
            Operator.Multiply(x.Imaginary, y)
        );
    }
    
    public static Complex<T> operator *(Complex<T> x, int y) 
    {
        return new Complex<T>(
            Operator.MultiplyAlternative(x.Real, y),
            Operator.MultiplyAlternative(x.Imaginary, y)
        );
    }
    
    private static T SquareLength(ref Complex<T> value) 
    {
        return Operator.Add(
            Operator.Multiply(value.Real, value.Real),
            Operator.Multiply(value.Imaginary, value.Imaginary)
        );
    }
    
    public static Complex<T> operator /(Complex<T> x, Complex<T> y) 
    {
        T divisor = SquareLength(ref y),
          real = Operator.Divide(
                Operator.Add(
                    Operator.Multiply(x.Real, y.Real),
                    Operator.Multiply(x.Imaginary, y.Imaginary)
                ), divisor),
          imaginary = Operator.Divide(
                Operator.Subtract(
                    Operator.Multiply(x.Imaginary, y.Real),
                    Operator.Multiply(x.Real, y.Imaginary)
                ), divisor);
        return new Complex<T>(real, imaginary);
    }
    
    public static Complex<T> operator /(Complex<T> x, T y) 
    {
        return new Complex<T>(
            Operator.Divide(x.Real, y),
            Operator.Divide(x.Imaginary, y)
        );
    }
    
    public static Complex<T> operator /(Complex<T> x, int y) 
    {
        return new Complex<T>(
            Operator.DivideInt32(x.Real, y),
            Operator.DivideInt32(x.Imaginary, y)
        );
    }
    
    public static implicit operator Complex<T>(T real) 
    {
        return new Complex<T>(real, Operator<T>.Zero);
    }

    public override int GetHashCode() 
    {
        return (Real == null ? 0 : 17 * Real.GetHashCode())
             + (Imaginary == null ? 0 : Imaginary.GetHashCode());
    }
}