public struct Complex
{
public static readonly Complex ZERO = new Complex(0, 0);
public static readonly Complex ONE = new Complex(1, 0);
public static readonly Complex i = new Complex(0, 1);
public static readonly Complex UNDEFINED = new Complex(Double.NaN, Double.NaN);
public readonly double Real;
public readonly double Image;
public Complex(double a_real, double a_image = 0)
{
Real = a_real;
Image = a_image;
}
public static bool operator ==(Complex a_a, Complex a_b)
{
return (a_a.Real == a_b.Real) & (a_a.Image == a_b.Image);
}
public static bool operator !=(Complex a_a, Complex a_b)
{
return (a_a.Real != a_b.Real) | (a_a.Image != a_b.Image);
}
public static Complex operator +(Complex a_a)
{
return a_a;
}
public static Complex FromPolar(double a_magnitude, double a_phase)
{
return new Complex(a_magnitude * Math.Cos(a_phase),
a_magnitude * Math.Sin(a_phase));
}
public static Complex FromPolar(double a_phase)
{
return new Complex(Math.Cos(a_phase), Math.Sin(a_phase));
}
public static Complex operator -(Complex a_a)
{
return new Complex(-a_a.Real, -a_a.Image);
}
public static Complex operator +(Complex a_a, Complex a_b)
{
return new Complex(
a_a.Real + a_b.Real,
a_a.Image + a_b.Image);
}
public static Complex operator -(Complex a_a, Complex a_b)
{
return new Complex(
a_a.Real - a_b.Real,
a_a.Image - a_b.Image);
}
public static Complex operator *(Complex a_a, Complex a_b)
{
return new Complex(
a_a.Real * a_b.Real - a_a.Image * a_b.Image,
a_a.Real * a_b.Image + a_a.Image * a_b.Real);
}
public static Complex operator *(Complex a_a, double a_b)
{
return new Complex(
a_a.Real * a_b,
a_a.Image * a_b);
}
public static Complex operator *(double a_a, Complex a_b)
{
return new Complex(
a_b.Real * a_a,
a_b.Image * a_a);
}
public static Complex operator /(Complex a_a, Complex a_b)
{
double den = a_b.Real * a_b.Real + a_b.Image * a_b.Image;
return new Complex(
(a_a.Real * a_b.Real + a_a.Image * a_b.Image) / den,
(a_a.Image * a_b.Real - a_a.Real * a_b.Image) / den);
}
public Complex Scale(double a_scale)
{
return new Complex(
Real * a_scale,
Image * a_scale);
}
public bool IsAlmostEquals(Complex a_a,
double a_precision = Constants.DOUBLE_PRECISION)
{
return Real.IsAlmostEquals(a_a.Real, a_precision) &&
Image.IsAlmostEquals(a_a.Image, a_precision);
}
public bool IsAlmostRelativeEquals(Complex a_a,
double a_precision = Constants.DOUBLE_PRECISION)
{
return Real.IsAlmostRelativeEquals(a_a.Real, a_precision) &&
Image.IsAlmostRelativeEquals(a_a.Image, a_precision);
}
public override int GetHashCode()
{
return Real.GetHashCode() ^ Image.GetHashCode();
}
public override bool Equals(object a_obj)
{
if (a_obj == null)
return false;
if (!typeof(Complex).Equals(a_obj.GetType()))
return false;
Complex complex = (Complex)a_obj;
return (complex.Real == Real) && (complex.Image == Image);
}
public bool Equals(Complex a_complex)
{
return (a_complex.Real == Real) && (a_complex.Image == Image);
}
[DebuggerHidden]
public Complex Conjugate
{
get
{
return new Complex(Real, -Image);
}
}
public double Abs
{
get
{
return MathExtensions.Hypot(Real, Image);
}
}
public double Phase
{
get
{
if (IsAlmostRelativeEquals(ZERO))
return Double.NaN;
return Math.Atan2(Image, Real);
}
}
public override string ToString()
{
if ((Real != 0) && (Image != 0))
return String.Format("({0} + {1}i)", Real, Image);
else if (Real != 0)
return Real.ToString();
else if (Image != 0)
return String.Format("{1}i", Image);
else
return "0";
}
}Testy:
[TestMethod]
public void Complex_Test()
{
// Constructor
{
Assert.AreEqual(4, new Complex(4).Real);
Assert.AreEqual(0, new Complex(4).Image);
Assert.AreEqual(5, new Complex(5, 6).Real);
Assert.AreEqual(6, new Complex(5, 6).Image);
}
// ==, !=
{
Assert.IsTrue(new Complex(5, 4) == new Complex(5, 4));
Assert.IsTrue(new Complex(5.3, 4.7) == new Complex(5.3, 4.7));
Assert.IsFalse(new Complex(5, 4) == new Complex(5, 5));
Assert.IsFalse(new Complex(5, 4) == new Complex(4, 4));
Assert.IsFalse(new Complex(5, 5) == new Complex(5, 4));
Assert.IsFalse(new Complex(4, 4) == new Complex(5, 4));
Assert.IsFalse(new Complex(5, 4) != new Complex(5, 4));
Assert.IsTrue(new Complex(5, 4) != new Complex(5, 5));
Assert.IsTrue(new Complex(5, 4) != new Complex(4, 4));
Assert.IsTrue(new Complex(5, 5) != new Complex(5, 4));
Assert.IsTrue(new Complex(4, 4) != new Complex(5, 4));
}
// unary -
{
Assert.IsTrue(new Complex(-1, 1) == -new Complex(1, -1));
Assert.IsTrue(new Complex(-1.6, 1.5) == -new Complex(1.6, -1.5));
Assert.IsTrue(new Complex(-1, -1) == -new Complex(1, 1));
Assert.IsTrue(new Complex(1, -1) == -new Complex(-1, 1));
Assert.IsTrue(new Complex(1, 0) == -new Complex(-1, 0));
Assert.IsTrue(new Complex(0, 0) == -new Complex(0, 0));
Assert.IsTrue(new Complex(0, 1) == -new Complex(0, -1));
Assert.IsTrue(-new Complex(-1, 1) == - -new Complex(1, -1));
Assert.IsTrue(-new Complex(-1, -1) == - -new Complex(1, 1));
Assert.IsTrue(-new Complex(1, -1) == - -new Complex(-1, 1));
Assert.IsTrue(-new Complex(1, 0) == - -new Complex(-1, 0));
Assert.IsTrue(-new Complex(0, 0) == - -new Complex(0, 0));
Assert.IsTrue(-new Complex(0, 1) == - -new Complex(0, -1));
}
// unary +
{
Assert.IsTrue(-new Complex(-1, 1) == +new Complex(1, -1));
Assert.IsTrue(-new Complex(-1, -1) == +new Complex(1, 1));
Assert.IsTrue(-new Complex(-1.2, -1.5) == +new Complex(1.2, 1.5));
Assert.IsTrue(-new Complex(1, -1) == +new Complex(-1, 1));
Assert.IsTrue(-new Complex(1, 0) == +new Complex(-1, 0));
Assert.IsTrue(-new Complex(0, 0) == +new Complex(0, 0));
Assert.IsTrue(-new Complex(0, 1) == +new Complex(0, -1));
}
// +
{
Assert.IsTrue(new Complex(0, 0) == new Complex(0, 0) + new Complex(0, 0));
Assert.IsTrue(new Complex(0, 1) == new Complex(0, 1) + new Complex(0, 0));
Assert.IsTrue(new Complex(0, 1) == new Complex(0, 0) + new Complex(0, 1));
Assert.IsTrue(new Complex(1, 0) == new Complex(1, 0) + new Complex(0, 0));
Assert.IsTrue(new Complex(1, 0) == new Complex(0, 0) + new Complex(1, 0));
Assert.IsTrue(new Complex(1, 1) == new Complex(1, 0) + new Complex(0, 1));
Assert.IsTrue(new Complex(1, 1) == new Complex(0, 1) + new Complex(1, 0));
Assert.IsTrue(new Complex(3, 3) == new Complex(1, 2) + new Complex(2, 1));
Assert.IsTrue(new Complex(4.1, 3.7) == new Complex(1.4, 2.6) +
new Complex(2.7, 1.1));
}
// -
{
Assert.IsTrue(new Complex(0, 0) == new Complex(0, 0) - -new Complex(0, 0));
Assert.IsTrue(new Complex(0, 1) == new Complex(0, 1) - -new Complex(0, 0));
Assert.IsTrue(new Complex(0, 1) == new Complex(0, 0) - -new Complex(0, 1));
Assert.IsTrue(new Complex(1, 0) == new Complex(1, 0) - -new Complex(0, 0));
Assert.IsTrue(new Complex(1, 0) == new Complex(0, 0) - -new Complex(1, 0));
Assert.IsTrue(new Complex(1, 1) == new Complex(1, 0) - -new Complex(0, 1));
Assert.IsTrue(new Complex(1, 1) == new Complex(0, 1) - -new Complex(1, 0));
Assert.IsTrue(new Complex(3, 3) == new Complex(1, 2) - -new Complex(2, 1));
Assert.IsTrue(new Complex(3.8, 3.8) == new Complex(1.7, 2.6) -
-new Complex(2.1, 1.2));
}
// * Complex
{
Assert.IsTrue(new Complex(0, 0) == new Complex(0, 0) * new Complex(0, 0));
Assert.IsTrue(new Complex(0, 0) == new Complex(0, 1) * new Complex(0, 0));
Assert.IsTrue(new Complex(0, 0) == new Complex(0, 0) * new Complex(0, 1));
Assert.IsTrue(new Complex(0, 0) == new Complex(1, 0) * new Complex(0, 0));
Assert.IsTrue(new Complex(0, 0) == new Complex(0, 0) * new Complex(1, 0));
Assert.IsTrue(new Complex(0, 1) == new Complex(1, 0) * new Complex(0, 1));
Assert.IsTrue(new Complex(0, 1) == new Complex(0, 1) * new Complex(1, 0));
Assert.IsTrue(new Complex(0, 5) == new Complex(1, 2) * new Complex(2, 1));
Assert.IsTrue(new Complex(-14, 31) == new Complex(2, 3) *
new Complex(5, 8));
AreAlmostRelativeEquals(new Complex(-14.32, 37.47),
new Complex(2.3, 3.2) * new Complex(5.6, 8.5));
}
// Complex * double, double * Complex, Scale
{
Action<Complex, Complex, double> scale_test = (c1, c2, s) =>
{
Assert.IsTrue(c1 == c2 * s);
Assert.IsTrue(c1 == s * c2);
Assert.IsTrue(c1 == c2.Scale(s));
};
scale_test(new Complex(0, 0), new Complex(0, 0), 0);
scale_test(new Complex(0, 0), new Complex(4, 4), 0);
scale_test(new Complex(0, 0), new Complex(4, 0), 0);
scale_test(new Complex(0, 0), new Complex(0, 4), 0);
scale_test(new Complex(0, 0), new Complex(0, 0), 4);
scale_test(new Complex(16, 16), new Complex(4, 4), 4);
scale_test(new Complex(16, 0), new Complex(4, 0), 4);
scale_test(new Complex(0, 16), new Complex(0, 4), 4);
scale_test(new Complex(0, 0), new Complex(0, 0), -4);
scale_test(new Complex(-16, -16), new Complex(4, 4), -4);
scale_test(new Complex(-16, 0), new Complex(4, 0), -4);
scale_test(new Complex(0, -16), new Complex(0, 4), -4);
scale_test(new Complex(-16, -12), new Complex(4, 3), -4);
scale_test(new Complex(-16, 12), new Complex(4, -3), -4);
scale_test(new Complex(16, -12), new Complex(-4, 3), -4);
scale_test(new Complex(17.63, -13.12), new Complex(-4.3, 3.2), -4.1);
}
// /
{
AreAlmostRelativeEquals(new Complex(23.0 / 41.0, 2.0 / 41.0),
new Complex(2, 3) / new Complex(4, 5));
AreAlmostRelativeEquals(new Complex(23.0 / 13.0, -2.0 / 13.0),
new Complex(4, 5) / new Complex(2, 3));
AreAlmostRelativeEquals(
new Complex(1.4896226415094338, -0.13867924528301892),
new Complex(4.4, 5.3) / new Complex(2.6, 3.8));
}
// IsAlmostEquals
{
Complex c = new Complex(0, 0);
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, -0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, -0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(0.5, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(0.5, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-0.5, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-0.5, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(0.5, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(0.5, -0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(-0.5, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(-0.5, -0.5) *
Constants.DOUBLE_PRECISION));
c = new Complex(40, -40);
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(2, -0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-2, -0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(0.5, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(0.5, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-0.5, 2) *
Constants.DOUBLE_PRECISION));
Assert.IsFalse(c.IsAlmostEquals(c + new Complex(-0.5, -2) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(0.5, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(0.5, -0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(-0.5, 0.5) *
Constants.DOUBLE_PRECISION));
Assert.IsTrue(c.IsAlmostEquals(c + new Complex(-0.5, -0.5) *
Constants.DOUBLE_PRECISION));
}
// IsAlmostRelativeEquals
{
Complex c = new Complex(1 / Constants.DOUBLE_PRECISION,
1 / Constants.DOUBLE_PRECISION);
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(2, 2)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(2, -2)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(-2, 2)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(-2, -2)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(2, 0.5)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(-2, 0.5)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(2, -0.5)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(-2, -0.5)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(0.5, 2)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(0.5, -2)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(-0.5, 2)));
Assert.IsFalse(c.IsAlmostRelativeEquals(c + new Complex(-0.5, -2)));
Assert.IsTrue(c.IsAlmostRelativeEquals(c + new Complex(0.5, 0.5)));
Assert.IsTrue(c.IsAlmostRelativeEquals(c + new Complex(0.5, -0.5)));
Assert.IsTrue(c.IsAlmostRelativeEquals(c + new Complex(-0.5, 0.5)));
Assert.IsTrue(c.IsAlmostRelativeEquals(c + new Complex(-0.5, -0.5)));
}
// Equals(obj), Equals(complex)
{
Assert.AreEqual(new Complex(5, 4), new Complex(5, 4));
Assert.AreEqual(new Complex(5.4, 4.4), new Complex(5.4, 4.4));
Assert.AreNotEqual(new Complex(5, 4), new Complex(5, 5));
Assert.AreNotEqual(new Complex(5, 4), new Complex(4, 4));
Assert.AreNotEqual(new Complex(5, 5), new Complex(5, 4));
Assert.AreNotEqual(new Complex(4, 4), new Complex(5, 4));
Assert.IsTrue(new Complex(5, 4).Equals(new Complex(5, 4)));
Assert.IsTrue(new Complex(5.3, 4.3).Equals(new Complex(5.3, 4.3)));
Assert.IsFalse(new Complex(5, 4).Equals(new Complex(5, 5)));
Assert.IsFalse(new Complex(5, 4).Equals(new Complex(4, 4)));
Assert.IsFalse(new Complex(5, 5).Equals(new Complex(5, 4)));
Assert.IsFalse(new Complex(4, 4).Equals(new Complex(5, 4)));
}
// Conjugate
{
Assert.IsTrue(new Complex(0, 0) == new Complex(0, 0).Conjugate);
Assert.IsTrue(new Complex(1, 0) == new Complex(1, 0).Conjugate);
Assert.IsTrue(new Complex(0, -1) == new Complex(0, 1).Conjugate);
Assert.IsTrue(new Complex(0, 1) == new Complex(0, -1).Conjugate);
Assert.IsTrue(new Complex(2, -3) == new Complex(2, 3).Conjugate);
Assert.IsTrue(new Complex(2, 3) == new Complex(2, -3).Conjugate);
Assert.IsTrue(new Complex(-2, -3) == new Complex(-2, 3).Conjugate);
Assert.IsTrue(new Complex(-2, 3) == new Complex(-2, -3).Conjugate);
Assert.IsTrue(new Complex(-2.2, 3.2) == new Complex(-2.2, -3.2).Conjugate);
}
// Abs
{
Assert.IsTrue(0 == new Complex(0, 0).Abs);
Assert.IsTrue(1 == new Complex(0, 1).Abs);
Assert.IsTrue(1 == new Complex(0, -1).Abs);
Assert.IsTrue(1 == new Complex(1, 0).Abs);
Assert.IsTrue(1 == new Complex(-1, 0).Abs);
Assert.IsTrue(5 == new Complex(3, 4).Abs);
Assert.IsTrue(5 == new Complex(-3, 4).Abs);
Assert.IsTrue(5 == new Complex(3, -4).Abs);
Assert.IsTrue(5 == new Complex(-3, -4).Abs);
Assert.IsTrue(2*MathExtensions.SQRT2 == new Complex(2, 2).Abs);
}
// Phase
{
Assert.AreEqual(Double.NaN,
MathExtensions.ToDeg(new Complex(0, 0).Phase));
Assert.AreEqual(Double.NaN,
MathExtensions.ToDeg(new Complex(Constants.DOUBLE_PRECISION / 2,
Constants.DOUBLE_PRECISION / 2).Phase));
Assert.AreEqual(0,
MathExtensions.ToDeg(new Complex(1, 0).Phase));
Assert.AreEqual(45,
MathExtensions.ToDeg(new Complex(1, 1).Phase));
Assert.AreEqual(90,
MathExtensions.ToDeg(new Complex(0, 1).Phase));
Assert.AreEqual(135,
MathExtensions.ToDeg(new Complex(-1, 1).Phase));
Assert.AreEqual(180,
MathExtensions.ToDeg(new Complex(-1, 0).Phase));
Assert.AreEqual(225 - 360,
MathExtensions.ToDeg(new Complex(-1, -1).Phase));
Assert.AreEqual(270 - 360,
MathExtensions.ToDeg(new Complex(0, -1).Phase));
Assert.AreEqual(315 - 360,
MathExtensions.ToDeg(new Complex(1, -1).Phase));
}
}







