Article

# Complex math library for C# and VB.NET

By , 15 Dec 2002
 Rate this:

## Introduction

The .NET platform doesn't have complex numbers built in. If you do scientific calculations such as groundwater modeling, complex numbers are essential. This article describes a full implementation of complex numbers for .NET, and how to use it with VB or C#.

Complex numbers have a real and imaginary part. Math operations are performed on complex numbers using special rules to keep track of the real and imaginary parts. Fortran and C++ have complex numbers built in.

## C# Example (cs_complex.cs)

```using System;
using KarlsTools;

class TestComplex{
static void Main(string[] args)
{
Complex c1 = new Complex(3.0, 4.0);
double d = Complex.Abs(c1);
Console.WriteLine("Test Complex,  d = "+ d);
}
}```

Compile and run the above code with the following commands:

```c:\>csc cs_complex.cs /r:complex.dll
C:\>cs_complex
Test Complex, d = 5```
 Complex Number Class for .NET List of Functionality C# Example```using System; using KarlsTools;``` C# output Constructor `Complex(double real, double imag)` `Complex c1 = new Complex(3,4);` c1 = (3,4) Methods `String ToString()` `string s = "c1 = "+c1.ToString();` s = c1 = (3,4) `Static double Abs(Complex c)` `double d = Complex.Abs(c1);` d = 5 `Static double Arg(Complex c)` `double d2 = Complex.Arg(c1);` d2 = 0.927295218001612 `Static Complex Conj(Complex c)` `Complex c2 = Complex.Conj(c1);` c2 = (3,-4) `Static double Imag(Complex c)` `double imag =Complex.Imag(c2);` imag = -4 `Static double Real(Complex c) ` `double real =Complex.Real(c1);` real = 3 `Double Imag()` `double imag2 = c1.Imag();` imag2 = 4 `Double Real() ` `double real2 = c1.Real();` real2 = 3 `Static Complex Polar(double r, double theta)` `Complex p = Complex.Polar(5,Math.PI/180);` p = (4.99924,0.087262) `Static Complex Cos(Complex c)` `Complex c3 = Complex.Cos(p);` c3 = (0.28401,0.0838028) `Static Complex Cosh(Complex c)` `Complex c4 = Complex.Cosh(p);` c4 = (73.8713,6.46199) `Static Complex Exp(Complex c)` `Complex c5 = Complex.Exp(p);` c5 = (147.736,12.9246) `Static Complex Log(Complex c)` `Complex c6 = Complex.Log(p);` c6 = (1.60944,0.0174533) `Static Complex Log10(Complex c)` `Complex c7 = Complex.Log10(p);` c7 = (0.69897,0.00757987) `Static double Norm(Complex c)` `double n = Complex.Norm(p);` n = 25 `Static Complex Pow(Complex base, double power)` `Complex c9 = Complex.Pow(p,4);` c9 = (623.478,43.5978) `Static Complex Pow(Complex base, Complex power)` `Complex c10 = Complex.Pow(p,p);` c10 = (3035.98,703.481) `Static Complex Pow(double base, Complex power)` `Complex c11 = Complex.Pow(2,p);` c11 = (31.9246,1.93333) `Static Complex Sin(Complex c)` `Complex c12 = Complex.Sin(p);` c12 = (-0.962794,0.0247206) `Static Complex Sinh(Complex c)` `Complex c13 = Complex.Sinh(p);` c13 = (73.8646,6.46257) `Static Complex Sqrt(Complex c)` `Complex c14 = Complex.Sqrt(p);` c14 = (2.23598,0.0195131) `Static Complex Tan(Complex c)` `Complex c15 = Complex.Tan(p);` c15 = (-3.09486,1.00024) `Static Complex Tanh(Complex c)` `Complex c15a = Complex.Tanh(p);` c15a = (0.99991,1.57891e-05) Operators `-` (Unary) `Complex c16 = -c15;` c16 = (3.09486,-1.00024) `+` (Unary) `Complex c17 = +c16;` c17 = (3.09486,-1.00024) `==` `bool eq = (c16 == -c15);` eq = True `==` (overloaded) `bool eq2 = ( new Complex(2,0) == 2);` eq2 = True `==` (overloaded) `bool eq3 = ( 2 == new Complex(2,0));` eq3 = True `!=` `bool ne = (c16 != c16);` ne = False `!=` (overloaded) `bool ne2 = ( new Complex(2,0) != 2);` ne2 = False `!=` (overloaded) `bool ne3 = ( 2 != new Complex(2,0));` ne3 = False `*` `Complex c18 = c1*c1;` c18 = (-7,24) `*` (overloaded) `Complex c19 = c1*double.PositiveInfinity;` c19 = (Infinity,Infinity) `*` (overloaded) `Complex c20 = 12*c1;` c20 = (36,48) `/` `Complex c21 = c1/c1;` c21 = (1,0) `/` (overloaded) `Complex c22 = c1/double.PositiveInfinity;` c22 = (0,0) `/` (overloaded) `Complex c23 = 1/c1;` c23 = (0.12,-0.16) `+` `Complex c24 = c1+c1;` c24 = (6,8) `+` (overloaded) `Complex c25 = c1+double.PositiveInfinity;` c25 = (Infinity,4) `+` (overloaded) `Complex c26 = 1+c1;` c26 = (4,4) `-` `Complex c27 = c1-c1;` c27 = (0,0) `-` (overloaded) `Complex c28 = c1-double.PositiveInfinity;` c28 = (-Infinity,4) `-` (overloaded) `Complex c29 = 1-c1;` c29 = (-2,-4)

## VB .NET Example (vb_complex.vb)

```Imports System
Imports KarlsTools

Module Module1

Sub Main()
Dim c1 As Complex = New Complex(3.0, 4.0)
dim d as Double = Complex.Abs(c1)
Console.WriteLine("Test Complex,  d = "& d.ToString())
End Sub
End Module```

Compile and run the above code with the following commands:

```c:\>vbc vb_complex.vb /r:complex.dll /r:System.dll
c:\>vb_complex.exe
Test Complex, d = 5```
 Complex Number Class for .NET List of Functionality Visual Basic Example VB output `Imports KarlsTools` Constructor `Complex(double real, double imag)` `Dim c1 As Complex = New Complex(3, 4)` c1 = (3,4) Methods `String ToString()` `Dim s As String = "c1 = " + c1.ToString()` s = c1 = (3,4) `shared double Abs(Complex c)` `Dim d As Double = Complex.Abs(c1)` d = 5 `shared double Arg(Complex c)` `Dim d2 As Double = Complex.Arg(c1)` d2 = 0.927295218001612 `shared Complex Conj(Complex c)` `Dim c2 As Complex = Complex.Conj(c1)` c2 = (3,-4) `shared double Imag(Complex c)` `Dim imag As Double = Complex.Imag(c2)` imag = -4 `shared double Real(Complex c) ` `Dim real As Double = Complex.Real(c1)` real = 3 `double Imag()` `Dim imag2 As Double = c1.Imag()` imag2 = 4 `double Real() ` `Dim real2 As Double = c1.Real()` real2 = 3 `shared Complex Polar(double r, double theta)` `Dim p As Complex = Complex.Polar(5, Math.PI / 180)` p = (4.99924,0.087262) `shared Complex Cos(Complex c)` `Dim c3 As Complex = Complex.Cos(p)` c3 = (0.28401,0.0838028) `shared Complex Cosh(Complex c)` `Dim c4 As Complex = Complex.Cosh(p)` c4 = (73.8713,6.46199) `shared Complex Exp(Complex c)` `Dim c5 As Complex = Complex.Exp(p)` c5 = (147.736,12.9246) `shared Complex Log(Complex c)` `Dim c6 As Complex = Complex.Log(p)` c6 = (1.60944,0.0174533) `shared Complex Log10(Complex c)` `Dim c7 As Complex = Complex.Log10(p)` c7 = (0.69897,0.00757987) `shared double Norm(Complex c)` `Dim n As Double = Complex.Norm(p)` n = 25 `shared Complex Pow(Complex base, double power)` `Dim c9 As Complex = Complex.Pow(p, 4)` c9 = (623.478,43.5978) `shared Complex Pow(Complex base, Complex power)` `Dim c10 As Complex = Complex.Pow(p, p)` c10 = (3035.98,703.481) `shared Complex Pow(double base, Complex power)` `Dim c11 As Complex = Complex.Pow(2, p)` c11 = (31.9246,1.93333) `shared Complex Sin(Complex c)` `Dim c12 As Complex = Complex.Sin(p)` c12 = (-0.962794,0.0247206) `shared Complex Sinh(Complex c)` `Dim c13 As Complex = Complex.Sinh(p)` c13 = (73.8646,6.46257) `shared Complex Sqrt(Complex c)` `Dim c14 As Complex = Complex.Sqrt(p)` c14 = (2.23598,0.0195131) `shared Complex Tan(Complex c)` `Dim c15 As Complex = Complex.Tan(p)` c15 = (-3.09486,1.00024) `shared Complex Tanh(Complex c)` `Dim c15a As Complex = Complex.Tanh(p)` c15a = (0.99991,1.57891e-05) Operators `-` (Unary) `Dim c16 As Complex = Complex.Negative(c15)` c16 = (3.09486,-1.00024) `+` (Unary) `Dim c17 As Complex = Complex.Plus(c16)` c17 = (3.09486,-1.00024) `==` `Dim eq As Boolean = c16.Equals(c17)` eq = True `==` (overloaded) `Dim eq2 As Boolean = (New Complex(2, 0)).Equals(2)` eq2 = True `==` (overloaded) `Dim eq3 As Boolean = Complex.Equals(2, New Complex(2, 0))` eq3 = True `!=` `Dim ne As Boolean = Complex.NotEqual(c16, c16)` ne = False `!=` (overloaded) `Dim ne2 As Boolean = Complex.NotEqual(New Complex(2, 0), 2)` ne2 = False `!=` (overloaded) `Dim ne3 As Boolean = Complex.NotEqual(2, New Complex(2, 0))` ne3 = False `*` `Dim c18 As Complex = Complex.Multiply(c1, c1)` c18 = (-7,24) `*` (overloaded) `Dim c19 As Complex = Complex.Multiply(c1, Double.PositiveInfinity)` c19 = (Infinity,Infinity) `*` (overloaded) `Dim c20 As Complex = Complex.Multiply(12, c1)` c20 = (36,48) `/` `Dim c21 As Complex = Complex.Divide(c1, c1)` c21 = (1,0) `/` (overloaded) `Dim c22 As Complex = Complex.Divide(c1, Double.PositiveInfinity)` c22 = (0,0) `/` (overloaded) `Dim c23 As Complex = Complex.Divide(1, c1)` c23 = (0.12,-0.16) `+` `Dim c24 As Complex = Complex.Add(c1, c1)` c24 = (6,8) `+` (overloaded) `Dim c25 As Complex = Complex.Add(c1, Double.PositiveInfinity)` c25 = (Infinity,4) `+` (overloaded) `Dim c26 As Complex = Complex.Add(1, c1)` c26 = (4,4) `-` `Dim c27 As Complex = Complex.Subtract(c1, c1)` c27 = (0,0) `-` (overloaded) `Dim c28 As Complex = Complex.Subtract(c1, Double.PositiveInfinity)` c28 = (-Infinity,4) `-` (overloaded) `Dim c29 As Complex = Complex.Subtract(1, c1)` c29 = (-2,-4)

## Implementation

This class is implemented using Managed C++. It duplicates the capabilities of the Fortran complex*16 type, and is a value type class with static (shared) math functions. This is how the .NET `Math` class is designed. Non-trivial methods are wrappers around the Standard Template Library (STL) `<complex>` class. The library has been tested with C# against all C++ STL <complex> sample output on Microsoft's web site.

Use either Visual Studio or the make file to compile the library (complex.dll). If you have Visual C++, open complex.vcproj and build. An alternate way to compile is by typing 'nmake' from a command prompt. A make file is included with the download.

## Issues when wrapping a C++ STL class for use with VB and C#

An easy way to provide complete functionality is to wrap the C++ STL <complex> class using Managed C++. This works well but wrapped methods run twice as slow as a method written from scratch. This is because the MSIL code generated by the C++ compiler has calls to the `System.Runtime.CompilerServices` to access the STL. I compromised by writing trivial methods from scratch and relied on the STL implementation otherwise.

This class duplicates the FORTRAN complex*16 type. Eight bytes for the real part, and 8 bytes for the imaginary part, by using `std::complex<double>`. This is not as flexible as the C++ STL class which allows `double`, `float`, or `int` to be used.

Extra code was added to provide VB functionality. The C++/C# operators `!=`, `==`, `+`, `-`, `*` and `/` didn't directly work in VB. I added methods: `NotEqual`, `Equals`, `Add`, `Subtract`, `Multiply` and `Divide` to provide complete functionality in VB. I do not understand why I needed to do this - please comment.

Other
United States
Karl is a Water Resources Engineer and Programmer. He holds a Masters degree in Civil Engineering, and is a Microsoft Certified Solution Developer.

 First PrevNext
 S....L....O....W.... mattsoundworld 14-Oct-11 3:34
 Updates and extensions bitzblitz 14-Sep-10 3:54
 Cool Hard Coder 15-Feb-10 9:01
 hi Jay200032 29-Mar-09 12:18
 Norm of 3 and 4 won`t be 25. vitamine1983 1-Nov-08 20:51
 Re: Norm of 3 and 4 won`t be 25. bitzblitz 14-Sep-10 4:09
 Convert Double Precision Trupti Mehta 7-Oct-08 20:45
 Help Vucina 7-Aug-08 12:30
 Re: Help Karl Tarbet 9-Aug-08 8:23
 Thank you davoodrajabi 2-Nov-07 20:35
 A Simple Pure C# Complex Class bossin 8-Jun-06 16:29
 //========================================================================// Copyright (c) 2005-2006, Boxing Wang. All rights reserved.//======================================================================== using System;using System.Diagnostics; namespace Wbx.Math{   [DebuggerDisplay("{Real} + {Imag}i")]   public struct Complex   {         public double Real;          public double Imag;          [DebuggerStepThrough()]         public Complex(double real, double imag)         {            this.Real = real;            this.Imag = imag;         }          [DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]         public Complex Conjugate         {            [DebuggerStepThrough()]            get { return new Complex(Real, -Imag); }         }          [DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]         public double Norm         {            [DebuggerStepThrough()]            get { return Real * Real + Imag * Imag; }         }          [DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]         public double Modulus         {            [DebuggerStepThrough()]            get { return System.Math.Sqrt(Real * Real + Imag * Imag); }         }       [DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]         public double Argument         {            [DebuggerStepThrough()]            get { return System.Math.Atan2(Imag, Real); }         }          [DebuggerStepThrough()]         public static Complex Polar(double modulus, double argument)         {            return new Complex(                  modulus * System.Math.Cos(argument),                  modulus * System.Math.Sin(argument));         }          public static Complex operator +(Complex z1, Complex z2)         {            return new Complex(z1.Real + z2.Real, z1.Imag + z2.Imag);         }          public static Complex operator -(Complex z1, Complex z2)         {            return new Complex(z1.Real - z2.Real, z1.Imag - z2.Imag);         }          public static Complex operator *(Complex z1, Complex z2)         {            return new Complex(                  z1.Real * z2.Real - z1.Imag * z2.Imag,                  z1.Real * z2.Imag + z1.Imag * z2.Real);         }          public static Complex operator /(Complex z1, Complex z2)         {            double value = z2.Real * z2.Real + z2.Imag * z2.Imag;             return new Complex(                  (z1.Real * z2.Real + z1.Imag * z2.Imag) / value,                  (z1.Imag * z2.Real - z1.Real * z2.Imag) / value);         }          public static bool operator ==(Complex z1, Complex z2)         {            return (z1.Real == z2.Real && z1.Imag == z2.Imag);         }          public static bool operator !=(Complex z1, Complex z2)         {            return (z1.Real != z2.Real || z1.Imag == z2.Imag);         }          public static Complex Cos(Complex z)         {            Complex z1 = Exp(new Complex(-z.Imag, z.Real));            Complex z2 = Exp(new Complex(z.Imag, -z.Real));             return new Complex(0.5 * (z1.Real + z2.Real), 0.5 * (z1.Imag + z2.Imag));         }          public static Complex Cosh(Complex z)         {            Complex z1 = Exp(z);            Complex z2 = Exp(new Complex(-z.Real, -z.Imag));             return new Complex(0.5 * (z1.Real + z2.Real), 0.5 * (z1.Imag + z2.Imag));         }          public static Complex Sin(Complex z)         {            Complex z1 = Exp(new Complex(-z.Imag, z.Real));            Complex z2 = Exp(new Complex(z.Imag, -z.Real));             return new Complex(0.5 * (z1.Imag - z2.Imag), 0.5 * (z2.Real - z1.Real));         }          public static Complex Sinh(Complex z)         {            Complex z1 = Exp(z);            Complex z2 = Exp(new Complex(-z.Real, -z.Imag));             return new Complex(0.5 * (z1.Real - z2.Real), 0.5 * (z1.Imag - z2.Imag));         }          public static Complex Tan(Complex z)         {            return Sin(z) / Cos(z);         }          public static Complex Tanh(Complex z)         {            return Sinh(z) / Cosh(z);         }          public static Complex Exp(Complex z)         {            double value = System.Math.Exp(z.Real);             return new Complex(                  value * System.Math.Cos(z.Imag),                  value * System.Math.Sin(z.Imag));         }          public static Complex Log(Complex z)         {            return new Complex(System.Math.Log(z.Modulus), z.Argument);         }          public static Complex Log10(Complex z)         {            const double log10 = 2.3025850929940459;             Complex value = Log(z);             value.Real /= log10;            value.Imag /= log10;             return value;         }          public static Complex Pow(Complex baseNumber, Complex index)         {            return Exp(index * Log(baseNumber));         }          public static Complex Sqrt(Complex z)         {            double value = System.Math.Sqrt(z.Real * z.Real + z.Imag * z.Imag) + z.Real;             return new Complex(                  System.Math.Sqrt(0.5 * value),                  System.Math.Sqrt(0.5 / value) * z.Imag);         }          public override string ToString()         {            return (String.Format("{0} + {1}i", Real, Imag));         }          public override bool Equals(object obj)         {            return base.Equals(obj);         }          public override int GetHashCode()         {            return Real.GetHashCode() ^ Imag.GetHashCode();         }   }}
 Re: A Simple Pure C# Complex Class boaza 14-Nov-07 21:17
 Re: A Simple Pure C# Complex Class `leppie` 12-Aug-08 0:19
 Re: A Simple Pure C# Complex Class thefellow3j 18-Oct-10 5:17
 Windows Forms support? Bill2005 31-Dec-05 20:24
 Re: Windows Forms support? Karl Tarbet 2-Jan-06 4:17
 Visual Studio 2005 support? Bill2005 31-Dec-05 20:18
 Re: Visual Studio 2005 support? Karl Tarbet 1-Jan-06 4:46
 Re: Visual Studio 2005 support? Bill2005 1-Jan-06 14:42
 I must say it's very good piece of work piotr.kolodziej 11-Dec-05 8:45
 You don't have to Doker 20-Oct-05 21:51
 american history indian Anonymous 7-Mar-05 13:31
 <complex> and managed code PDHB 12-Oct-03 15:43
 This seems, well, too complex Marc Clifton 16-Dec-02 3:37
 Re: This seems, well, too complex Karl Tarbet 16-Dec-02 13:24
 Last Visit: 31-Dec-99 18:00     Last Update: 19-Apr-14 7:05 Refresh 12 Next »