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)); } }