Complex numbers arise in algebra in the solution of quadratic equations.
The equation x2 = -1 does not have
any real solutions. However, if we define a new number, i
as the square root of -1, then we have two solutions: i
and -i. This, in turn, gives rise to an entirely new class
of numbers of the form a + ib with a and
b real, and i defined as above.
These are the complex numbers.
The Extreme Optimization Numerical Libraries for .NET
provides one generic type for complex numbers of any type:
The ComplexT.
Constructing complex numbers
The ComplexT
structure has three constructors.
The first constructor takes two arguments: the real and imaginary parts
of the complex number.
var z1 = new Complex<double>(3.0, 4.0);
Dim z1 As Complex(Of Double) = New Complex(Of Double)(3.0, 4.0)
No code example is currently available or this language may not be supported.
let z1 = Complex<double>(3.0, 4.0)
The second constructor takes one real argument. It constructs
a complex number whose imaginary part is zero.
var z2 = new Complex<double>(3.0);
Dim z2 As Complex(Of Double) = New Complex(Of Double)(3.0)
No code example is currently available or this language may not be supported.
let z2 = Complex<double>(3.0)
Complex numbers can also be created from the polar form:
the static FromPolar
method takes two arguments: the magnitude and phase of the complex number.
var z3 = Complex<double>.FromPolar(3.0, Constants.Pi / 6.0);
Dim z3 As Complex(Of Double) = Complex(Of Double).FromPolar(3.0, Constants.Pi / 6.0)
No code example is currently available or this language may not be supported.
let z3 = Complex<double>.FromPolar(3.0, Constants.Pi / 6.0)
Finally, the static
RootOfUnity
method constructs a complex number that is one of the solutions
to the equation
xn = 1
.
The solutions to this equation are n complex numbers
spaced equally on the unit circle. The first parameter of the method
is the degree, n, of the root. The second parameter
is the index of the root in the series, counting counter-clockwise
on the unit circle. An index of 0 corresponds to the root
x = 1.
The complex structure provides several read-only fields for commonly used
and special complex numbers. These are listed in the following table:
Complex number constants
Field | Description |
---|
I |
The number i, the square root of 1.
|
Zero |
Complex`1 zero: 0 + 0i.
|
One |
Complex one: 1 + 0i.
|
Infinity | Complex infinity. |
NaN | Complex Not-a-Number. |
Two values in the above list deserve special attention.
The Infinity
field represents complex infinity.
It is the result of dividing any non-zero complex number by zero.
Complex infinity does not have a sign. Because the complex numbers
do not have a natural ordering, is does not make sense to speak of
positive or negative numbers.
Directed infinities, where the magnitude of the complex number
is infinite, but its argument is not, are not supported.
Direct comparison with Infinity
is not recommended. Instead, use the static
IsInfinity
method.
The NaN
field represents complex Not-a-Number. It is a special value that
is the result of dividing zero by zero.
Comparisons with Not-a-Number always return false.
The static
IsNaN
method verifies whether a complex number equals Complex<T>.NaN.
You can not use the equality operator for this purpose, as it always returns
false.
Working with complex numbers
Working with complex numbers is easy. The
Re
property gets the real part of the complex number, while
Im
gets the imaginary part.
The Magnitude
property returns the square root of the magnitude (absolute value, modulus).
The Phase
property returns the phase (argument of the complex number:
the angle between the positive real axis and a line
from the origin to the complex number, measured counter-clockwise.
The magnitude is computed every time the
magnitude property is called.
The same is true for the Argument property.
If you use these values multiple times, you should consider caching them
in a variable.
Details of complex arithmetic
When performing binary operations,
if one of the operands is a complex number,
then the other operand is required to be either a complex number
of the same type, or a real number that can be converted to
or a floating-point type (Double or
Single) or a complex type (ComplexT). Prior
to performing the operation, if the other operand is not a complex number, it is converted to
complex number, and the operation is performed using at least complex number range and
precision. If the operation produces a numerical result, the type of the result is complex number.
Exceptions to this are methods that return a real property of a number:
Magnitude,
Phase,
MagnitudeSquared and
Abs.
In these cases, the return type is
Double.
The Extreme Optimization Numerical Libraries for .NET extends the IEEE-754 standard definition of NaN's
for real numbers to complex numbers as follows.
The floating-point operators, including the assignment operators, do not throw exceptions. Instead, in exceptional
situations, the result of a floating-point operation is zero, Infinity, or NaN, as
described below:
-
If the result of a complex floating-point operation is too small for the destination format, the result of the
operation is zero.
-
If the magnitude of the complex result of a floating-point operation is too large for the destination format,
the result of the operation is Complex<T>.Infinity.
-
If a complex floating-point operation on complex numbers is invalid, the result of the operation is
Complex<T>.NaN.
-
If one or both operands of a complex floating-point operation are NaN (real or complex), the
result of the operation is Complex<T>.NaN.
Overloaded operators for all basic arithmetic operators
on complex numbers are available. Most contain overloads
for cases where one of the operands is real.
Corresponding static methods are provided for languages
that don't support operator overloading.
For example, here is some C# code:
var a = new Complex<double>(1, 2);
var b = new Complex<double>(-3, 4);
var c = 2 - 1 / (a + b);
Dim a As Complex(Of Double) = New Complex(Of Double)(1, 2)
Dim b As Complex(Of Double) = New Complex(Of Double)(-3, 4)
Dim c As Complex(Of Double) = 2 - 1 / (a + b)
No code example is currently available or this language may not be supported.
let a = Complex<double>(1.0, 2.0)
let b = Complex<double>(-3.0, 4.0)
let c = 2.0 - 1.0 / (a + b)
and here is the equivalent Visual Basic.NET code:
[Visual Basic]
a Complex( Double)(1, 2)
b Complex( Double)(-3, 4)
c
ComplexT= _
Complex`1.Subtract(2, Complex`1.Divide(1, Complex`1.Add(a, b)))
Specific to complex numbers is the static
Conjugate
method. This method returns the conjugate of a complex number,
leaving the original unchanged.
Complex number operators and their static (Shared) method equivalents
Operator | Static method equivalent | Description |
---|
+z | (no equivalent) |
Returns the complex number z.
|
-z | Negate |
Returns the negation of the complex number z.
|
z1 + z2 | Complex<T>.Add(z1, z2) |
Adds the complex numbers z1 and z2.
|
z + a | Complex<T>.Add(z, a) |
Adds the complex number z and the real number a.
|
a + z | Complex<T>.Add(a, z) |
Adds the real number a to the complex number z.
|
z++ | (no equivalent) |
Increments the complex number z by one.
|
z1 - z2 | Complex<T>.Subtract(z1, z2) |
Subtracts the complex numbers z1 and z2.
|
z - a | Complex<T>.Subtract(z, a) |
Subtracts the real number a from the complex number z.
|
a - z | Complex<T>.Subtract(a, z) |
Subtracts the complex number z from the real number a.
|
z-- | (no equivalent) |
Decrements the complex number z by one.
|
z1 * z2 | Complex<T>.Multiply(z1, z2) |
Multiplies the complex numbers z1 and z2.
|
z * a | Complex<T>.Multiply(z, a) |
Multiplies the complex number z and the real number a.
|
a * z | Complex<T>.Multiply(a, z) |
Multiplies the real number a and the complex number z.
|
z1 / z2 | Complex<T>.Divide(z1, z2) |
Divides the complex number z1 by z2.
|
z / a | Complex<T>.Divide(z, a) |
Divides the complex number z by the real number a.
|
a / z | Complex<T>.Divide(a, z) |
Divides the real number a by the complex number z.
|
~z | Conjugate |
Returns the complex conjugate of the complex number z.
|
There is one other static method that does not have
an operator equivalent. The
ConjugateMultiply
method returns the product of the conjugate
of the first argument and the second argument.
Because the complex numbers don't have a natural ordering,
only equality and inequality operators are available.
No other comparison operators are available.
Functions of complex numbers
The ComplexT
type defines static methods for the most common
mathematical functions of complex numbers, including:
logarithmic, exponential, trigonometric and hyperbolic functions.
Some functions of real numbers have a limited domain
when the result is restricted to be real, but are defined for
all real numbers if the result can be complex. Examples of this are
the inverse sine and cosine, which are real only for arguments
between -1 and +1. The
ComplexT
type defines methods that extend these functions to return a
complex result.
These functions are often discontinuous along the part
of the real axis where they are complex-valued. Which
of the two limit values is chosen is arbitrary. However,
the most consistent choice is the one that preserves
any symmetry or anti-symmetry about the origin.
For example, the function Arcsin(x) satisfies
Arcsin(-x) = -Arcsin(x) when x is within
the interval [-1, 1]. The Arcsin method
with real argument also satisfies this identity.
Most elementary functions have been extended to cover
the entire complex plane. Once again, many of them are
multi-valued, and a suitable choice has to be made
regarding which of the two possible limit values is returned.
The choice is made easier by the fact that the discontinuities
lie along the real or imaginary axis. This makes it possible
to distinguish between the 'limit from above' and
the 'limit from below' by using the value of negative zero
for the limit from below. The situation is somewhat simplified
by the fact that any analytic function satisfies the
identity f(conj(z) = conj(f(z)).
The tables below summarize these methods, and their meaning.
Special functions with complex argument may be
available from the
Special
class.
Logarithmic and exponential functions of complex numbers.
Method | Description |
---|
Exp |
The number E raised to the complex power
z.
|
ExpI |
The number E raised to I times the real number a.
|
RootOfUnity |
The number E raised to I times TwoPi*i/n.
|
Sqrt |
The first square root of the complex number z.
|
Sqrt |
The first square root of the real number a, which may be negative.
|
Pow |
The complex number z1 raised to the complex power z2.
|
Pow |
The complex number z raised to the real power a.
|
Pow |
The complex number z raised to the integer power n.
|
Log |
Natural logarithm of the complex number z.
|
Log |
Base z1 logarithm of the complex number z2.
|
Log10 |
Base 10 (common) logarithm of the complex number z.
|
Trigonometric functions of complex numbers
Method | Description |
---|
Sin |
Sine of the complex number z.
|
Cos |
Cosine of the complex number z.
|
Tan |
Tangent of the complex number z.
|
Asin |
Inverse sine of the complex number z.
|
Asin |
Inverse sine of the real number a.
|
Acos |
Inverse cosine of the complex number z.
|
Acos |
Inverse cosine of the real number a.
|
Atan |
Inverse tangent of the complex number z.
|
Hyperbolic functions of complex numbers
Method | Description |
---|
Sinh |
Hyperbolic sine of the complex number z.
|
Cosh |
Hyperbolic cosine of the complex number z.
|
Tanh |
Hyperbolic tangent of the complex number z.
|
Asinh |
Inverse hyperbolic sine of the complex number z.
|
Acosh |
Inverse hyperbolic cosine of the complex number z.
|
Atanh |
Inverse hyperbolic tangent of the complex number z.
|
Complex numbers of arbitrary type
The ComplexT
structure is generic over the type of the real numbers. This makes it possible
to create complex numbers of different precisions, or even complex integers.
All that is needed is to specify the desired real type in the constructor:
var q1 = new Complex<Quad>(1.0, Quad.Sqrt(3));
var pi = 3 * q1.Phase;
Dim q1 As Complex(Of Quad) = New Complex(Of Quad)(1.0, Quad.Sqrt(3))
Dim pi As Complex(Of Quad) = 3 * q1.Phase
No code example is currently available or this language may not be supported.
let q1 = Complex<Quad>(Quad.One, Quad.Sqrt(Quad(3)))
let pi = Quad(3.0) * q1.Phase