Since this question was asked a while ago, but I am sure there are others who are interested in this topic, I decided to post the implementation for complex numbers in C# I have made recently.
Because complex numbers are value types, I used a struct instead of a class (a struct is faster in this case, which I found out with the help of a simple app I wrote running a Mandelbrot algorithm [see links below the answer] to measure it) and have overloaded operators like +, -, *, / as well as comparison operators <, >, =, !=, == so you can use them seamlessly (however because complex numbers are two-dimensional, < and > will compare against the squared amount, while == and != compare against equality).
I have used double precision, because fractal graphic and such require high accuracy. But you could also use single precision if that's sufficient for your application.
Note that this requires to override GetHashCode() and Equals(object obj) as well. I have also overloaded ++ and -- operators, although in the complex world there are several possible ways to interpret this: increment/decrement real and imaginary parts or just one of them?
Also I have created an implicit conversion between a tuple (a, bi) and the complex numbers so you can easily initialize them like:
complex a = (1, 2), b = (3, 4); // via tuples (re, im)
You can even parse strings like:
string input = Console.ReadLine();
if (!complex.TryParse(input, out complex c))
Console.WriteLine("Syntax error");
else
Console.WriteLine($"Parsed value for c = {c}");
Then you can use them as simply as
var w = a - b; Console.WriteLine($"a - b = {w}");
var x = a + b; Console.WriteLine($"a + b = {x}");
var y = a * b; Console.WriteLine($"a * b = {y}");
var z = a / b; Console.WriteLine($"a / b = {z}");
Giving you the output
a - b = -2 - 2i
a + b = 4 + 6i
a * b = -5 + 10i
a / b = 0.44 + 0.08i
You can even write a for loop just as (notice you have 2 dimensions!):
for (complex u = (0,0); u <= (5, 5); u.Re++, u.Im++)
{
Console.WriteLine(u);
}
And if comparisons are also possible:
if (u==(1, 1)) Console.WriteLine("u == 1+i");
The required class is implemented as follows:
/// <summary>
/// Complex numbers
/// Written by Matt, 2022
///
/// https://stackoverflow.com/a/70936453/1016343
/// </summary>
struct complex
{
public double Re, Im;
public complex(double re, double im)
{
this.Re = re; this.Im = im;
}
public static complex operator ++(complex c) { ++c.Re; ++c.Im; return c; } // not the only way one can implement this
public static complex operator --(complex c) { --c.Re; --c.Im; return c; } // not the only way one can implement this
public static complex operator +(complex a, complex b) => new complex(a.Re + b.Re, a.Im + b.Im);
public static complex operator -(complex a, complex b) => new complex(a.Re - b.Re, a.Im - b.Im);
public static double AmountSqr(complex c) => c.Re * c.Re + c.Im + c.Im;
public static double Amount(complex c) => Math.Sqrt(AmountSqr(c));
/// <summary>Compares the amount of both complex numbers, returns true if |a|<|b|.</summary>
public static bool operator <(complex a, complex b) => AmountSqr(a) < AmountSqr(b);
/// <summary>Compares the amount of both complex numbers, returns true if |a|>|b|.</summary>
public static bool operator >(complex a, complex b) => AmountSqr(a) > AmountSqr(b);
/// <summary>Compares the both complex numbers, returns true if a == b.</summary>
public static bool operator ==(complex a, complex b) => (a.Re == b.Re && a.Im == b.Im);
/// <summary>Compares the both complex numbers, returns true if a != b.</summary>
public static bool operator !=(complex a, complex b) => (a.Re != b.Re || a.Im != b.Im);
// (a+bi)(c+di) = ac-bd + (ad+bc)i
public static complex operator *(complex a, complex b)
=> new complex(a.Re*b.Re-a.Im*b.Im, a.Re*b.Im+a.Im*b.Re);
// (a+bi)/(c+di) = (ac+bd)/(c*c + d*d) + i(bc-ad)/(c*c + d*d)
public static complex operator /(complex a, complex b)
{
var divisor = (b.Re * b.Re + b.Im * b.Im);
return new complex((a.Re*b.Re+a.Im*b.Im)/divisor, (a.Im*b.Re-a.Re*b.Im)/divisor);
}
public static implicit operator complex((double real, double imag) c)
=> new complex(c.real, c.imag); // via tuples (re, im)
public override string ToString()
=> $"{this.Re.ToString().Trim()} {(this.Im < 0 ? "-" : "+")} {Math.Abs(this.Im)}i";
/// <summary>Tries to convert string expressions like "2+3i" or "5-7i" to complex</summary>
public static bool TryParse(string complexNr, out complex result)
{
bool success = false;
result = (0, 0);
try
{
result = Parse(complexNr);
success = true;
} catch {}
return success;
}
/// <summary>Converts string expressions like "2+3i" or "5-7i" to complex</summary>
public static complex Parse(string complexNr)
{
complex result = (0, 0);
try
{
if (complexNr.Contains("-")) complexNr = complexNr.Replace("-", "+-");
var tr = complexNr.Split("+").Select(s => s.Trim()).ToArray();
var realStr = tr[0]; var imagStr = tr[1].TrimEnd('i').Trim();
result = (double.Parse(realStr), double.Parse(imagStr));
}
catch (Exception ex)
{
throw new SyntaxErrorException("Invalid syntax for complex number. Allowed is 'a+bi' or 'a-bi'", ex);
}
return result;
}
public override bool Equals(object obj)
{
return (obj == null) ? false : (this == (complex)obj);
}
public override int GetHashCode()
{
var hash = new HashCode();
hash.Add(this.Re); hash.Add(this.Im);
return hash.ToHashCode();
}
}
References (Mandelbrot algorithms to measure performance of "complex" library):
- Mandelbrot set (Python, but understandable for C# programmers too)
- Mandelbrot algorithms (Pseudocode)
Complexclass should define valid operations. If the rules are the same then how is that different from a "complex number"?