/Utilities/Math/Complex.cs
C# | 772 lines | 496 code | 86 blank | 190 comment | 11 complexity | aa8bafbcfffb7ea3c00cffd7e17a57b9 MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- using Delta.Utilities.Helpers;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Math
- {
- /// <summary>
- /// Complex number with real and imaginary parts as floats. Rarely used,
- /// but can be useful for complex mathematical problems.
- /// </summary>
- [StructLayout(LayoutKind.Explicit)]
- [DebuggerDisplay("Complex(Real={Real}, Imaginary={Imaginary})")]
- public struct Complex : ISaveLoadBinary, IEquatable<Complex>
- {
- #region Constants
- /// <summary>
- /// Represents the size in bytes of each Complex (2 * 4 = 8 bytes).
- /// </summary>
- public const int DataSize = 2 * 4;
-
- /// <summary>
- /// Returns a Complex with all values filled to zero
- /// </summary>
- public static readonly Complex Zero =
- new Complex(0, 0);
- #endregion
-
- #region FromSqrt (Static)
- /// <summary>
- /// From sqrt
- /// </summary>
- public static Complex FromSqrt(float setR)
- {
- return new Complex(
- setR >= 0.0f
- ? MathHelper.Sqrt(setR)
- : 0.0f,
- setR < 0.0f
- ? MathHelper.Sqrt(-setR)
- : 0.0f);
- }
- #endregion
-
- #region Real (Public)
- /// <summary>
- /// Real
- /// </summary>
- [FieldOffset(0)]
- public float Real;
- #endregion
-
- #region Imaginary (Public)
- /// <summary>
- /// Imaginary
- /// </summary>
- [FieldOffset(4)]
- public float Imaginary;
- #endregion
-
- #region LengthSquared (Public)
- /// <summary>
- /// Length squared
- /// </summary>
- public float LengthSquared
- {
- get
- {
- return Real * Real + Imaginary * Imaginary;
- }
- }
- #endregion
-
- #region Length (Public)
- /// <summary>
- /// Length
- /// </summary>
- public float Length
- {
- get
- {
- return MathHelper.Sqrt(Real * Real + Imaginary * Imaginary);
- }
- }
- #endregion
-
- #region Argument (Public)
- /// <summary>
- /// Argument
- /// </summary>
- public float Argument
- {
- get
- {
- return MathHelper.Atan(Imaginary, Real);
- }
- }
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create complex
- /// </summary>
- public Complex(float setR, float setI)
- {
- Real = setR;
- Imaginary = setI;
- }
-
- /// <summary>
- /// Create complex from phasor values.
- /// </summary>
- public Complex(float setModulus, float setArgument, bool phasorDummy)
- {
- Real = setModulus * MathHelper.Cos(setArgument);
- Imaginary = setModulus * MathHelper.Sin(setArgument);
- }
- #endregion
-
- #region IEquatable<Complex> Members
- /// <summary>
- /// Equals
- /// </summary>
- /// <param name="other">Other</param>
- /// <returns>Value indicating the equality of two vectors</returns>
- public bool Equals(Complex other)
- {
- return Real == other.Real &&
- Imaginary == other.Imaginary;
- }
- #endregion
-
- #region ISaveLoadBinary Members
- /// <summary>
- /// Load real and imaginary part of this complex number from a stream.
- /// </summary>
- public void Load(BinaryReader reader)
- {
- Real = reader.ReadSingle();
- Imaginary = reader.ReadSingle();
- }
-
- /// <summary>
- /// Save real and imaginary part of this complex number to a stream.
- /// </summary>
- public void Save(BinaryWriter writer)
- {
- writer.Write(Real);
- writer.Write(Imaginary);
- }
- #endregion
-
- #region op_UnaryNegation (Operator)
- /// <summary>
- /// Op unary negation
- /// </summary>
- public static Complex operator -(Complex value1)
- {
- return new Complex(-value1.Real, -value1.Imaginary);
- }
- #endregion
-
- #region op_UnaryPlus (Operator)
- /// <summary>
- /// Op unary plus
- /// </summary>
- public static Complex operator +(Complex value1)
- {
- return new Complex(+value1.Real, +value1.Imaginary);
- }
- #endregion
-
- #region op_Addition (Operator)
- /// <summary>
- /// Op addition
- /// </summary>
- public static Complex operator +(Complex value1, Complex value2)
- {
- return new Complex(value1.Real + value2.Real,
- value1.Imaginary + value2.Imaginary);
- }
- #endregion
-
- #region op_Subtraction (Operator)
- /// <summary>
- /// Op subtraction
- /// </summary>
- public static Complex operator -(Complex value1, Complex value2)
- {
- return new Complex(value1.Real - value2.Real,
- value1.Imaginary - value2.Imaginary);
- }
- #endregion
-
- #region op_Multiply (Operator)
- /// <summary>
- /// Op multiply
- /// </summary>
- public static Complex operator *(Complex value1, Complex value2)
- {
- return
- new Complex(value1.Real * value2.Real - value1.Imaginary * value2.Imaginary,
- value1.Real * value2.Imaginary + value2.Real * value1.Imaginary);
- }
-
- /// <summary>
- /// Op multiply
- /// </summary>
- public static Complex operator *(Complex value1, float scalar)
- {
- return new Complex(value1.Real * scalar, value1.Imaginary * scalar);
- }
-
- /// <summary>
- /// Op multiply
- /// </summary>
- public static Complex operator *(float scalar, Complex value1)
- {
- return new Complex(value1.Real * scalar, value1.Imaginary * scalar);
- }
- #endregion
-
- #region op_Division (Operator)
- /// <summary>
- /// Op division
- /// </summary>
- public static Complex operator /(Complex value1, Complex value2)
- {
- float invertedSquared = 1.0f / value2.LengthSquared;
- return new Complex(
- (value1.Real * value2.Real + value1.Imaginary * value2.Imaginary) *
- invertedSquared,
- (value1.Imaginary * value2.Real - value1.Real * value2.Imaginary) *
- invertedSquared);
- }
-
- /// <summary>
- /// Op division
- /// </summary>
- public static Complex operator /(Complex value1, float scalar)
- {
- float Is = 1.0f / scalar;
- return new Complex(value1.Real * Is, value1.Imaginary * Is);
- }
- #endregion
-
- #region op_Equality (Operator)
- /// <summary>
- /// Check for equality
- /// </summary>
- /// <param name="value1">Value 1</param>
- /// <param name="value2">Value 2</param>
- /// <returns>True if the values are equal, false otherwise</returns>
- public static bool operator ==(Complex value1, Complex value2)
- {
- return value1.Real == value2.Real &&
- value1.Imaginary == value2.Imaginary;
- }
- #endregion
-
- #region op_Inequality (Operator)
- /// <summary>
- /// Check for inequality
- /// </summary>
- /// <param name="value1">Value 1</param>
- /// <param name="value2">Value 2</param>
- /// <returns>Bool</returns>
- public static bool operator !=(Complex value1, Complex value2)
- {
- return value1.Real != value2.Real ||
- value1.Imaginary != value2.Imaginary;
- }
- #endregion
-
- #region Min (Public)
- /// <summary>
- /// Minimum
- /// </summary>
- public float Min()
- {
- return MathHelper.Min(Real, Imaginary);
- }
-
- /// <summary>
- /// Minimum
- /// </summary>
- public void Min(Complex other)
- {
- Real = MathHelper.Min(Real, other.Real);
- Imaginary = MathHelper.Min(Imaginary, other.Imaginary);
- }
- #endregion
-
- #region Max (Public)
- /// <summary>
- /// Maximum
- /// </summary>
- public float Max()
- {
- return MathHelper.Max(Real, Imaginary);
- }
-
- /// <summary>
- /// Maximum
- /// </summary>
- public void Max(Complex other)
- {
- Real = MathHelper.Max(Real, other.Real);
- Imaginary = MathHelper.Max(Imaginary, other.Imaginary);
- }
- #endregion
-
- #region Sum (Public)
- /// <summary>
- /// Sum
- /// </summary>
- public float Sum()
- {
- return Real + Imaginary;
- }
- #endregion
-
- #region Product (Public)
- /// <summary>
- /// Product
- /// </summary>
- public float Product()
- {
- return Real * Imaginary;
- }
- #endregion
-
- #region Conjugate (Public)
- /// <summary>
- /// Conjugate
- /// </summary>
- public Complex Conjugate()
- {
- return new Complex(Real, -Imaginary);
- }
- #endregion
-
- #region Sqrt (Public)
- /// <summary>
- /// Sqrt
- /// </summary>
- public Complex Sqrt()
- {
- return new Complex(MathHelper.Pow(LengthSquared, 0.25f),
- 0.5f * Argument, true);
- }
- #endregion
-
- #region ToString (Public)
- /// <summary>
- /// To string
- /// </summary>
- public override string ToString()
- {
- return Real.ToString() + " + i * " + Imaginary.ToString();
- }
- #endregion
-
- #region GetHashCode (Public)
- /// <summary>
- /// Get hash code
- /// </summary>
- public override int GetHashCode()
- {
- return Real.GetHashCode() ^ (Imaginary.GetHashCode() * 7);
- }
- #endregion
-
- #region Equals (Public)
- /// <summary>
- /// Equals
- /// </summary>
- public override bool Equals(object obj)
- {
- if (obj is Complex)
- {
- return Equals((Complex)obj);
- }
- return base.Equals(obj);
- }
- #endregion
-
- /// <summary>
- /// Tests
- /// </summary>
- internal class ComplexTests
- {
- #region TestCreate
- /// <summary>
- /// Test Constructors
- /// </summary>
- [Test]
- public void TestCreate()
- {
- // Create complex
- Complex complex = new Complex(1.0f, 5.0f);
-
- // Make sure the values are correct
- Assert.NearlyEqual(complex.Real, 1.0f);
- Assert.NearlyEqual(complex.Imaginary, 5.0f);
- }
- #endregion
-
- #region Equality
- /// <summary>
- /// Equality
- /// </summary>
- [Test]
- public void Equality()
- {
- Complex c1 = new Complex(1.0f, 2.0f);
- Complex c2 = new Complex(1.0f, 2.0f);
- Complex c3 = new Complex(1.5f, 2.0f);
-
- Assert.True(c1 == c2);
- Assert.False(c1 == c3);
- }
- #endregion
-
- #region Inequality
- /// <summary>
- /// Inequality
- /// </summary>
- [Test]
- public void Inequality()
- {
- Complex c1 = new Complex(1.0f, 2.0f);
- Complex c2 = new Complex(1.0f, 2.0f);
- Complex c3 = new Complex(1.5f, 2.0f);
-
- Assert.False(c1 != c2);
- Assert.True(c1 != c3);
- }
- #endregion
-
- #region ScalarDivison
- /// <summary>
- /// Scalar divison
- /// </summary>
- [Test]
- public void ScalarDivison()
- {
- Complex c1 = new Complex(6.0f, 20.0f);
- float scalar = 2.0f;
- Complex result = c1 / scalar;
-
- Assert.NearlyEqual(result.Real, 3.0f);
- Assert.NearlyEqual(result.Imaginary, 10.0f);
- }
- #endregion
-
- #region ComplexDivision
- /// <summary>
- /// Complex division
- /// </summary>
- [Test]
- public void ComplexDivision()
- {
- float r1 = 12.0f;
- float i1 = 20.0f;
- float r2 = 2.0f;
- float i2 = 4.0f;
-
- Complex c1 = new Complex(r1, i1);
- Complex c2 = new Complex(r2, i2);
- Complex result = c1 / c2;
-
- // Source: http://de.wikipedia.org/wiki/Komplexe_Zahl#Division
- float rResult = ((r1 * r2) + (i1 * i2)) / ((r2 * r2) + (i2 * i2));
- float iResult = ((i1 * r2) - (r1 * i2)) / ((r2 * r2) + (i2 * i2));
-
- Assert.NearlyEqual(result.Real, rResult);
- Assert.NearlyEqual(result.Imaginary, iResult);
- }
- #endregion
-
- #region ScalarMultiply
- /// <summary>
- /// Scalar multiplyScalar
- /// </summary>
- [Test]
- public void ScalarMultiply()
- {
- Complex c1 = new Complex(6.0f, 20.0f);
- float scalar = 2.0f;
- Complex result = c1 * scalar;
- // Test reverse too
- Complex result2 = scalar * c1;
-
- Assert.NearlyEqual(result.Real, 12.0f);
- Assert.NearlyEqual(result.Imaginary, 40.0f);
-
- Assert.NearlyEqual(result2.Real, 12.0f);
- Assert.NearlyEqual(result2.Imaginary, 40.0f);
- }
- #endregion
-
- #region ComplexMultiply
- /// <summary>
- /// Complex multiply
- /// </summary>
- [Test]
- public void ComplexMultiply()
- {
- float r1 = 1.0f;
- float i1 = 2.0f;
- float r2 = 4.0f;
- float i2 = 8.0f;
-
- Complex c1 = new Complex(r1, i1);
- Complex c2 = new Complex(r2, i2);
- Complex result = c1 * c2;
-
- // Source: http://de.wikipedia.org/wiki/Komplexe_Zahl#Multiplikation
- float rResult = (r1 * r2) - (i1 * i2);
- float iResult = (r1 * i2) + (i1 * r2);
-
- Assert.NearlyEqual(result.Real, rResult);
- Assert.NearlyEqual(result.Imaginary, iResult);
- }
- #endregion
-
- #region ComplexSubtract
- /// <summary>
- /// Complex subtract
- /// </summary>
- [Test]
- public void ComplexSubtract()
- {
- float r1 = 10.0f;
- float i1 = 20.0f;
- float r2 = 5.0f;
- float i2 = 7.0f;
-
- Complex c1 = new Complex(r1, i1);
- Complex c2 = new Complex(r2, i2);
- Complex result = c1 - c2;
-
- // Source: http://de.wikipedia.org/wiki/Komplexe_Zahl#Subtraktion
- float rResult = r1 - r2;
- float iResult = i1 - i2;
-
- Assert.NearlyEqual(result.Real, rResult);
- Assert.NearlyEqual(result.Imaginary, iResult);
- }
- #endregion
-
- #region ComplexAddition
- /// <summary>
- /// Complex addition
- /// </summary>
- [Test]
- public void ComplexAddition()
- {
- float r1 = 10.0f;
- float i1 = 20.0f;
- float r2 = 5.0f;
- float i2 = 7.0f;
-
- Complex c1 = new Complex(r1, i1);
- Complex c2 = new Complex(r2, i2);
- Complex result = c1 + c2;
-
- // Source: http://de.wikipedia.org/wiki/Komplexe_Zahl#Addition
- float rResult = r1 + r2;
- float iResult = i1 + i2;
-
- Assert.NearlyEqual(result.Real, rResult);
- Assert.NearlyEqual(result.Imaginary, iResult);
- }
- #endregion
-
- #region DataSize
- /// <summary>
- /// Data size
- /// </summary>
- [Test]
- public void DataSize()
- {
- int calculatedDatasize = sizeof(float) + sizeof(float);
- Assert.Equal(calculatedDatasize, Complex.DataSize);
- }
- #endregion
-
- #region ComplexMin
- /// <summary>
- /// Complex minimum
- /// </summary>
- [Test]
- public void ComplexMin()
- {
- float r1 = 1.0f;
- float i1 = 5.0f;
- float r2 = 2.0f;
- float i2 = 3.0f;
-
- Complex c1 = new Complex(r1, i1);
- Complex c2 = new Complex(r2, i2);
- c1.Min(c2);
-
- Assert.NearlyEqual(c1.Real, r1);
- Assert.NearlyEqual(c1.Imaginary, i2);
- }
- #endregion
-
- #region ComplexMax
- /// <summary>
- /// Complex maximum
- /// </summary>
- [Test]
- public void ComplexMax()
- {
- float r1 = 1.0f;
- float i1 = 5.0f;
- float r2 = 2.0f;
- float i2 = 3.0f;
-
- Complex c1 = new Complex(r1, i1);
- Complex c2 = new Complex(r2, i2);
- c1.Max(c2);
-
- Assert.NearlyEqual(c1.Real, r2);
- Assert.NearlyEqual(c1.Imaginary, i1);
- }
- #endregion
-
- #region Sum
- /// <summary>
- /// Complex sum
- /// </summary>
- [Test]
- public void Sum()
- {
- float r1 = 1.0f;
- float i1 = 5.0f;
- Complex c1 = new Complex(r1, i1);
-
- Assert.NearlyEqual(c1.Sum(), r1 + i1);
- }
- #endregion
-
- #region Product
- /// <summary>
- /// Product
- /// </summary>
- [Test]
- public void Product()
- {
- float r1 = 2.0f;
- float i1 = 5.0f;
- Complex c1 = new Complex(r1, i1);
-
- Assert.NearlyEqual(c1.Product(), r1 * i1);
- }
- #endregion
-
- #region LengthSquared
- /// <summary>
- /// Length squared
- /// </summary>
- [Test]
- public void LengthSquared()
- {
- float r1 = 2.0f;
- float i1 = 5.0f;
- Complex c1 = new Complex(r1, i1);
-
- Assert.NearlyEqual(c1.LengthSquared, (r1 * r1) + (i1 * i1));
- }
- #endregion
-
- #region Length
- /// <summary>
- /// Length
- /// </summary>
- [Test]
- public void Length()
- {
- float r1 = 2.0f;
- float i1 = 5.0f;
- Complex c1 = new Complex(r1, i1);
-
- Assert.NearlyEqual(c1.Length,
- MathHelper.Sqrt((r1 * r1) + (i1 * i1)));
- }
- #endregion
-
- #region FromSqrt
- /// <summary>
- /// From sqrt
- /// </summary>
- [Test]
- public void FromSqrt()
- {
- float square = 4.0f;
- Complex c1 = Complex.FromSqrt(square);
- Complex c2 = Complex.FromSqrt(-square);
-
- Assert.Equal(c1, new Complex(MathHelper.Sqrt(square), 0.0f));
- Assert.Equal(c2, new Complex(0.0f, MathHelper.Sqrt(square)));
- }
- #endregion
-
- #region Argument
- /// <summary>
- /// Argument
- /// </summary>
- [Test]
- public void Argument()
- {
- float r1 = 2.0f;
- float i1 = 5.0f;
- float result = (new Complex(r1, i1)).Argument;
-
- Assert.NearlyEqual(result, MathHelper.Atan(i1, r1));
- }
- #endregion
-
- #region Conjugate
- /// <summary>
- /// Conjugate
- /// </summary>
- [Test]
- public void Conjugate()
- {
- float r1 = 2.0f;
- float i1 = 5.0f;
- Complex c1 = new Complex(r1, i1).Conjugate();
-
- Assert.NearlyEqual(c1.Real, r1);
- Assert.NearlyEqual(c1.Imaginary, -i1);
- }
- #endregion
-
- #region Sqrt
- /// <summary>
- /// Sqrt
- /// </summary>
- [Test]
- public void Sqrt()
- {
- float r1 = 2.0f;
- float i1 = 5.0f;
- Complex c1 = new Complex(r1, i1).Sqrt();
- float modulus = (float)System.Math.Pow((r1 * r1) + (i1 * i1), 0.25f);
- float argument = 0.5f * MathHelper.Atan(i1, r1);
-
- Assert.NearlyEqual(c1.Real, modulus * MathHelper.Cos(argument));
- Assert.NearlyEqual(c1.Imaginary, modulus * MathHelper.Sin(argument));
- }
- #endregion
-
- #region ToString
- /// <summary>
- /// To string
- /// </summary>
- [Test]
- public new void ToString()
- {
- Assert.Equal("5 + i * 2", new Complex(5.0f, 2.0f).ToString());
- }
- #endregion
- }
- }
- }