From 1374a450c46130e94f20c19febbc9183ed922dc8 Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Mon, 27 Jul 2009 17:22:27 +0800 Subject: [PATCH] complex: fixed ToString and added operators Signed-off-by: Marcus Cuda --- src/Managed.UnitTests/ComplexTest.cs | 299 +++++++++++++++++++++- src/Managed/Complex.cs | 369 +++++++++++++++++++++++++-- src/Managed/SpecialFunctions.cs | 24 ++ 3 files changed, 670 insertions(+), 22 deletions(-) diff --git a/src/Managed.UnitTests/ComplexTest.cs b/src/Managed.UnitTests/ComplexTest.cs index 7c9f0def..0457e8cd 100644 --- a/src/Managed.UnitTests/ComplexTest.cs +++ b/src/Managed.UnitTests/ComplexTest.cs @@ -1,7 +1,9 @@ -namespace MathNet.Numerics.UnitTests -{ - using MbUnit.Framework; +using System; +using System.Globalization; +using MbUnit.Framework; +namespace MathNet.Numerics.UnitTests +{ [TestFixture] public class ComplexTest { @@ -9,8 +11,295 @@ public void CanCreateComplexNumberUsingTheConstructor() { var complex = new Complex(1.1, -2.2); - Assert.AreEqual(complex.Real, 1.1, "Real part is 1.1"); - Assert.AreEqual(complex.Imaginary, -2.2, "Imaginary part is -2.2"); + Assert.AreEqual(1.1, complex.Real, "Real part is 1.1."); + Assert.AreEqual(-2.2, complex.Imaginary, "Imaginary part is -2.2."); + } + + [Test, MultipleAsserts] + public void CanCreateComplexNumberWithRealImaginaryIntializer() + { + var complex = Complex.WithRealImaginary(1.1, -2.2); + Assert.AreEqual(1.1, complex.Real, "Real part is 1.1."); + Assert.AreEqual(-2.2, complex.Imaginary, "Imaginary part is -2.2."); + } + + [Test] + public void WithModulusArgumentThrowsArgumentOutOfRangeException() + { + Assert.Throws(() => Complex.WithModulusArgument(-1, 1), "Throws exception because modulus is negative."); + } + + [Test, MultipleAsserts] + public void CanCreateComplexNumberWithModulusArgument() + { + var complex = Complex.WithModulusArgument(2, -Math.PI / 6); + Assert.AreApproximatelyEqual(Math.Sqrt(3), complex.Real, 1e-15, "Real part is Sqrt(3)."); + Assert.AreApproximatelyEqual(-1, complex.Imaginary, 1e-15, "Imaginary part is -1."); + } + + [Test] + public void CanDetermineIfZeroValueComplexNumber() + { + var complex = new Complex(0, 0); + Assert.IsTrue(complex.IsZero, "Zero complex number."); + } + + [Test] + public void CanDetermineIfOneValueComplexNumber() + { + var complex = new Complex(1, 0); + Assert.IsTrue(complex.IsOne, "Complex number with a value of one."); + } + + [Test] + public void CanDetermineIfImaginaryUnit() + { + var complex = new Complex(0, 1); + Assert.IsTrue(complex.IsI, "Imaginary unit"); + } + + [Test, MultipleAsserts] + public void CanDetermineIfNaN() + { + var complex = new Complex(double.NaN, 1); + Assert.IsTrue(complex.IsNaN, "Real part is NaN."); + complex = new Complex(1, double.NaN); + Assert.IsTrue(complex.IsNaN, "Imaginary part is NaN."); + complex = new Complex(double.NaN, double.NaN); + Assert.IsTrue(complex.IsNaN, "Both parts are NaN."); + } + + [Test, MultipleAsserts] + public void CanDetermineIfInfinity() + { + var complex = new Complex(double.PositiveInfinity, 1); + Assert.IsTrue(complex.IsInfinity, "Real part is infinity."); + complex = new Complex(1, double.NegativeInfinity); + Assert.IsTrue(complex.IsInfinity, "Imaginary part is infinity."); + complex = new Complex(double.NegativeInfinity, double.PositiveInfinity); + Assert.IsTrue(complex.IsInfinity, "Both parts are infinity."); + } + + [Test] + public void CanDetermineIfRealNumber() + { + var complex = new Complex(-1, 0); + Assert.IsTrue(complex.IsReal, "Is a real number."); + } + + [Test] + public void CanDetermineIfRealNonNegativeNumber() + { + var complex = new Complex(1, 0); + Assert.IsTrue(complex.IsReal, "Is a real non-negative number."); + } + + [Test, MultipleAsserts] + public void CanCalculateHashCode() + { + var complex = new Complex(1, 0); + Assert.AreEqual(1072693248, complex.GetHashCode()); + complex = new Complex(0, 1); + Assert.AreEqual(-1072693248, complex.GetHashCode()); + complex = new Complex(1, 1); + Assert.AreEqual(-2097152, complex.GetHashCode()); + } + + [Test, MultipleAsserts] + public void CanCreateStringFromComplexNumber() + { + Assert.AreEqual("NaN", Complex.NaN.ToString()); + Assert.AreEqual("Infinity", Complex.Infinity.ToString()); + Assert.AreEqual("1.1", new Complex(1.1, 0).ToString()); + Assert.AreEqual("-1.1i", new Complex(0, -1.1).ToString()); + Assert.AreEqual("1.1i", new Complex(0, 1.1).ToString()); + Assert.AreEqual("1.1 + 1.1i", new Complex(1.1, 1.1).ToString()); + } + + [Test, MultipleAsserts] + public void CanTestForEquality() + { + Assert.AreNotEqual(Complex.NaN, Complex.NaN); + Assert.AreEqual(Complex.Infinity, Complex.Infinity); + Assert.AreEqual(new Complex(1.1, -2.2), new Complex(1.1, -2.2)); + Assert.AreNotEqual(new Complex(-1.1, 2.2), new Complex(1.1, -2.2)); + } + + [Test, MultipleAsserts] + public void CanCreateStringUsingNumberFormat() + { + Assert.AreEqual("NaN", Complex.NaN.ToString("#.000")); + Assert.AreEqual("Infinity", Complex.Infinity.ToString("#.000")); + Assert.AreEqual("1.100", new Complex(1.1, 0).ToString("#.000")); + Assert.AreEqual("-1.100i", new Complex(0, -1.1).ToString("#.000")); + Assert.AreEqual("1.100i", new Complex(0, 1.1).ToString("#.000")); + Assert.AreEqual("1.100 + 1.100i", new Complex(1.1, 1.1).ToString("#.000")); + } + + [Test, MultipleAsserts] + public void CanCreateStringUsingFormatProvider() + { + var provider = CultureInfo.GetCultureInfo("tr-TR"); + Assert.AreEqual("NaN", Complex.NaN.ToString(provider)); + Assert.AreEqual("Infinity", Complex.Infinity.ToString(provider)); + Assert.AreEqual("1,1", new Complex(1.1, 0).ToString(provider)); + Assert.AreEqual("-1,1i", new Complex(0, -1.1).ToString(provider)); + Assert.AreEqual("1,1i", new Complex(0, 1.1).ToString(provider)); + Assert.AreEqual("1,1 + 1,1i", new Complex(1.1, 1.1).ToString(provider)); + } + + [Test, MultipleAsserts] + public void CanTestForEqualityUsingOperators() + { + AssertEx.That(() => Complex.NaN != Complex.NaN); + AssertEx.That(() => Complex.Infinity == Complex.Infinity); + AssertEx.That(() => new Complex(1.1, -2.2) == new Complex(1.1, -2.2)); + AssertEx.That(() => new Complex(-1.1, 2.2) != new Complex(1.1, -2.2)); + } + + [Test, MultipleAsserts] + public void CanConvertDoubleToComplex() + { + AssertEx.That(() => ((Complex) double.NaN).IsNaN); + AssertEx.That(() => ((Complex) double.NegativeInfinity).IsInfinity); + Assert.AreEqual((Complex) 1.1, new Complex(1.1, 0)); + } + + [Test] + public void CanUsePlusOperator() + { + var complex = new Complex(1.1, -2.2); + Assert.AreEqual(complex, +complex); + } + + [Test] + public void CanNegateValueUsingOperator() + { + var complex = new Complex(1.1, -2.2); + Assert.AreEqual(new Complex(-1.1, 2.2), -complex); + } + + [Test] + public void CanUsePlus() + { + var complex = new Complex(1.1, -2.2); + Assert.AreEqual(complex, complex.Plus()); + } + + [Test] + public void CanNegateValue() + { + var complex = new Complex(1.1, -2.2); + Assert.AreEqual(new Complex(-1.1, 2.2), complex.Negate()); + } + + [Test, MultipleAsserts] + public void CanAddTwoComplexNumbersUsingOperartor() + { + AssertEx.That(() => (Complex.NaN + Complex.NaN).IsNaN); + AssertEx.That(() => (Complex.Infinity + Complex.One).IsInfinity); + AssertEx.That(() => (Complex.One + Complex.Zero) == Complex.One); + AssertEx.That(() => (new Complex(1.1, -2.2) + new Complex(-1.1, 2.2)) == Complex.Zero); + } + + [Test, MultipleAsserts] + public void CanAddTwoComplexNumbers() + { + AssertEx.That(() => (Complex.NaN.Add(Complex.NaN)).IsNaN); + AssertEx.That(() => (Complex.Infinity.Add(Complex.One).IsInfinity)); + AssertEx.That(() => (Complex.One.Add(Complex.Zero)) == Complex.One); + AssertEx.That(() => (new Complex(1.1, -2.2).Add(new Complex(-1.1, 2.2))) == Complex.Zero); + } + + [Test, MultipleAsserts] + public void CanAddComplexNumberAndDoubleUsingOperartor() + { + AssertEx.That(() => (Complex.NaN + double.NaN).IsNaN); + AssertEx.That(() => (double.NaN + Complex.NaN).IsNaN); + AssertEx.That(() => (double.PositiveInfinity + Complex.One).IsInfinity); + AssertEx.That(() => (Complex.Infinity + 1.0).IsInfinity); + AssertEx.That(() => (Complex.One + 0.0) == Complex.One); + AssertEx.That(() => (0.0 + Complex.One) == Complex.One); + AssertEx.That(() => (new Complex(1.1, -2.2) + 1.1 == new Complex(2.2, -2.2))); + AssertEx.That(() => -2.2 + new Complex(-1.1, 2.2) == new Complex(-3.3, 2.2)); + } + + [Test, MultipleAsserts] + public void CanAddSubtractComplexNumbersUsingOperartor() + { + AssertEx.That(() => (Complex.NaN - Complex.NaN).IsNaN); + AssertEx.That(() => (Complex.Infinity - Complex.One).IsInfinity); + AssertEx.That(() => (Complex.One - Complex.Zero) == Complex.One); + AssertEx.That(() => (new Complex(1.1, -2.2) - new Complex(1.1, -2.2)) == Complex.Zero); + } + + [Test, MultipleAsserts] + public void CanSubtractTwoComplexNumbers() + { + AssertEx.That(() => (Complex.NaN.Subtract(Complex.NaN)).IsNaN); + AssertEx.That(() => (Complex.Infinity.Subtract(Complex.One)).IsInfinity); + AssertEx.That(() => (Complex.One.Subtract(Complex.Zero)) == Complex.One); + AssertEx.That(() => (new Complex(1.1, -2.2).Subtract(new Complex(1.1, -2.2))) == Complex.Zero); + } + + [Test, MultipleAsserts] + public void CanSubtractComplexNumberAndDoubleUsingOperartor() + { + AssertEx.That(() => (Complex.NaN - double.NaN).IsNaN); + AssertEx.That(() => (double.NaN - Complex.NaN).IsNaN); + AssertEx.That(() => (double.PositiveInfinity - Complex.One).IsInfinity); + AssertEx.That(() => (Complex.Infinity - 1.0).IsInfinity); + AssertEx.That(() => (Complex.One - 0.0) == Complex.One); + AssertEx.That(() => (0.0 - Complex.One) == -Complex.One); + AssertEx.That(() => (new Complex(1.1, -2.2) - 1.1 == new Complex(0.0, -2.2))); + AssertEx.That(() => -2.2 - new Complex(-1.1, 2.2) == new Complex(-1.1, -2.2)); + } + + [Test, MultipleAsserts] + public void CanMultipleTwoComplexNumbersUsingOperators() + { + AssertEx.That(() => (Complex.NaN * Complex.One).IsNaN); + Assert.AreEqual(new Complex(0, 16), new Complex(4, -4) * new Complex(-2, 2)); + } + + [Test, MultipleAsserts] + public void CanMultipleTwoComplexNumbers() + { + AssertEx.That(() => (Complex.NaN.Multiply(Complex.One).IsNaN)); + Assert.AreEqual(new Complex(0, 16), new Complex(4, -4).Multiply(new Complex(-2, 2))); + } + + [Test, MultipleAsserts] + public void CanMultipleComplexNumberAndDoubleUsingOperators() + { + AssertEx.That(() => (Complex.NaN * 1.0).IsNaN); + Assert.AreEqual(new Complex(8, -8), new Complex(4, -4) * 2); + Assert.AreEqual(new Complex(8, -8), 2 * new Complex(4, -4)); + } + + [Test, MultipleAsserts] + public void CanDivideTwoComplexNumbersUsingOperators() + { + AssertEx.That(() => (Complex.NaN / Complex.One).IsNaN); + Assert.AreEqual(new Complex(-2, 0), new Complex(4, -4) / new Complex(-2, 2)); + Assert.AreEqual(Complex.Infinity, Complex.One / Complex.Zero); + } + + [Test, MultipleAsserts] + public void CanDivideTwoComplexNumbers() + { + AssertEx.That(() => (Complex.NaN.Multiply(Complex.One).IsNaN)); + Assert.AreEqual(new Complex(-2, 0), new Complex(4, -4).Divide(new Complex(-2, 2))); + Assert.AreEqual(Complex.Infinity, Complex.One.Divide(Complex.Zero)); + } + + [Test, MultipleAsserts] + public void CanDivideComplexNumberAndDoubleUsingOperators() + { + AssertEx.That(() => (Complex.NaN * 1.0).IsNaN); + Assert.AreEqual(new Complex(-2, 2), new Complex(4, -4) / -2); + Assert.AreEqual(new Complex(0.25, 0.25), 2 / new Complex(4, -4)); + Assert.AreEqual(Complex.Infinity, Complex.One / 0); } } } \ No newline at end of file diff --git a/src/Managed/Complex.cs b/src/Managed/Complex.cs index 05c38dcf..04f8060c 100644 --- a/src/Managed/Complex.cs +++ b/src/Managed/Complex.cs @@ -229,7 +229,7 @@ namespace MathNet.Numerics /// true if this instance is I; otherwise, false. public bool IsI { - get { return _real.AlmostZero() && _imag.AlmostEqual(1); } + get { return _real.AlmostZero() && _imag.AlmostEqual(1.0); } } /// @@ -247,7 +247,7 @@ namespace MathNet.Numerics /// infinite value. /// /// - /// true if this instance is infinie; otherwise, false. + /// true if this instance is infinite; otherwise, false. /// /// /// True if it either evaluates to a complex infinity @@ -279,14 +279,100 @@ namespace MathNet.Numerics } /// - /// Gets a value indicating whetherthe provided Complex is imaginary. + /// Gets the conjugate of this Complex. /// - /// - /// true if this instance is an imaginary number; otherwise, false. - /// - public bool IsImaginary + /// + /// The semantic of setting the conjugate is such that + /// + /// // a, b of type Complex + /// a.Conjugate = b; + /// + /// is equivalent to + /// + /// // a, b of type Complex + /// a = b.Conjugate + /// + /// + public Complex Conjugate + { + get { return new Complex(_real, -_imag); } + } + + /// + /// Gets or modulus of this Complex. + /// + /// + public double Modulus { - get { return _real.AlmostZero(); } + get { return Math.Sqrt((_real * _real) + (_imag * _imag)); } + } + + /// + /// Gets the squared modulus of this Complex. + /// + /// + public double ModulusSquared + { + get { return (_real * _real) + (_imag * _imag); } + } + + /// + /// Gets argument of this Complex. + /// + /// + /// Argument always returns a value bigger than negative Pi and + /// smaller or equal to Pi. If this Complex is zero, the Complex + /// is assumed to be positive _real with an argument of zero. + /// + public double Argument + { + get + { + if (IsReal && _real < 0) + { + return Math.PI; + } + + return IsRealNonNegative ? 0 : Math.Atan2(_imag, _real); + } + } + + /// + /// Gets the unity of this complex (same argument, but on the unit circle; exp(I*arg)) + /// + public Complex Sign + { + get + { + if (double.IsPositiveInfinity(_real) && double.IsPositiveInfinity(_imag)) + { + return new Complex(Constants.Sqrt1Over2, Constants.Sqrt1Over2); + } + + if (double.IsPositiveInfinity(_real) && double.IsNegativeInfinity(_imag)) + { + return new Complex(Constants.Sqrt1Over2, -Constants.Sqrt1Over2); + } + + if (double.IsNegativeInfinity(_real) && double.IsPositiveInfinity(_imag)) + { + return new Complex(-Constants.Sqrt1Over2, -Constants.Sqrt1Over2); + } + + if (double.IsNegativeInfinity(_real) && double.IsNegativeInfinity(_imag)) + { + return new Complex(-Constants.Sqrt1Over2, Constants.Sqrt1Over2); + } + + // don't replace this with "Modulus"! + var mod = SpecialFunctions.Hypotenuse(_real, _imag); + if (mod.AlmostZero()) + { + return Zero; + } + + return new Complex(_real / mod, _imag / mod); + } } #region Static Initializers @@ -376,18 +462,28 @@ namespace MathNet.Numerics var ret = new StringBuilder(); - ret.Append(_real.ToString(format, formatProvider)); - if (_imag < 0) + if (!_real.AlmostZero()) { - ret.Append(" "); + ret.Append(_real.ToString(format, formatProvider)); } - else + + if (!_imag.AlmostZero()) { - ret.Append(" + "); + if (!_real.AlmostZero()) + { + if (_imag < 0) + { + ret.Append(" "); + } + else + { + ret.Append(" + "); + } + } + + ret.Append(_imag.ToString(format, formatProvider)).Append("i"); } - ret.Append(_imag.ToString(format, formatProvider)).Append("i"); - return ret.ToString(); } @@ -406,7 +502,15 @@ namespace MathNet.Numerics /// The complex number to compare to with. public bool Equals(Complex other) { - return Real == other.Real && Imaginary == other.Imaginary; + if (IsNaN || other.IsNaN) + { + return false; + } + if( IsInfinity && other.IsInfinity ) + { + return true; + } + return _real.AlmostEqual(other._real) && _imag.AlmostEqual(other._imag); } /// The hash code for the complex number. @@ -431,7 +535,238 @@ namespace MathNet.Numerics /// The complex number to compare to with. public override bool Equals(object obj) { - return (obj is Complex) && Equals((Complex)obj); + return (obj is Complex) && Equals((Complex) obj); + } + + #endregion + + #region Operators + + /// + /// Equality test. + /// + /// One of complex numbers to compare. + /// The other complex numbers to compare. + /// true if the real and imaginary components of the two complex numbers are equal; false otherwise. + public static bool operator ==(Complex complex1, Complex complex2) + { + return complex1.Equals(complex2); + } + + /// + /// Inequality test. + /// + /// One of complex numbers to compare. + /// The other complex numbers to compare. + /// true if the real or imaginary components of the two complex numbers are not equal; false otherwise. + public static bool operator !=(Complex complex1, Complex complex2) + { + return !complex1.Equals(complex2); + } + + /// + /// Unary addition. + /// + /// The complex number to operate on. + /// Returns the same complex number. + public static Complex operator +(Complex summand) + { + return summand; + } + + /// + /// Unary minus. + /// + /// The complex number to operate on. + /// The negated value of the . + public static Complex operator -(Complex subtrahend) + { + return new Complex(-subtrahend._real, -subtrahend._imag); + } + + /// Addition operator. Adds two complex numbers together. + /// The result of the addition. + /// One of the complex numbers to add. + /// The other complex numbers to add. + public static Complex operator +(Complex summand1, Complex summand2) + { + return new Complex(summand1._real + summand2._real, summand1._imag + summand2._imag); + } + + /// Subtraction operator. Subtracts two complex numbers. + /// The result of the subtraction. + /// The complex number to subtract from. + /// The complex number to subtract. + public static Complex operator -(Complex minuend, Complex subtrahend) + { + return new Complex(minuend._real - subtrahend._real, minuend._imag - subtrahend._imag); + } + + /// Addition operator. Adds a complex number and double together. + /// The result of the addition. + /// The complex numbers to add. + /// The double value to add. + public static Complex operator +(Complex summand1, double summand2) + { + return new Complex(summand1._real + summand2, summand1._imag); + } + + /// Subtraction operator. Subtracts double value from a complex value. + /// The result of the subtraction. + /// The complex number to subtract from. + /// The double value to subtract. + public static Complex operator -(Complex minuend, double subtrahend) + { + return new Complex(minuend._real - subtrahend, minuend._imag); + } + + /// Addition operator. Adds a complex number and double together. + /// The result of the addition. + /// The double value to add. + /// The complex numbers to add. + public static Complex operator +(double summand1, Complex summand2) + { + return new Complex(summand2._real + summand1, summand2._imag); + } + + /// Subtraction operator. Subtracts complex value from a double value. + /// The result of the subtraction. + /// The double vale to subtract from. + /// The complex value to subtract. + public static Complex operator -(double minuend, Complex subtrahend) + { + return new Complex(minuend - subtrahend._real, -subtrahend._imag); + } + + /// Multiplication operator. Multiplies two complex numbers. + /// The result of the multiplication. + /// One of the complex numbers to multiply. + /// The other complex number to multiply. + public static Complex operator *(Complex multiplicand, Complex multiplier) + { + return new Complex((multiplicand._real * multiplier._real) - (multiplicand._imag * multiplier._imag), (multiplicand._real * multiplier._imag) + (multiplicand._imag * multiplier._real)); + } + + /// Multiplication operator. Multiplies a complex number with a double value. + /// The result of the multiplication. + /// The double value to multiply. + /// The complex number to multiply. + public static Complex operator *(double multiplicand, Complex multiplier) + { + return new Complex(multiplier._real * multiplicand, multiplier._imag * multiplicand); + } + + /// Multiplication operator. Multiplies a complex number with a double value. + /// The result of the multiplication. + /// The complex number to multiply. + /// The double value to multiply. + public static Complex operator *(Complex multiplicand, double multiplier) + { + return new Complex(multiplicand._real * multiplier, multiplicand._imag * multiplier); + } + + /// Division operator. Divides a complex number by another. + /// The result of the division. + /// The dividend. + /// The divisor. + public static Complex operator /(Complex dividend, Complex divisor) + { + if (divisor.IsZero) + { + return Infinity; + } + + var modSquared = divisor.ModulusSquared; + return new Complex(((dividend._real * divisor._real) + (dividend._imag * divisor._imag)) / modSquared, ((dividend._imag * divisor._real) - (dividend._real * divisor._imag)) / modSquared); + } + + /// Division operator. Divides a double value by a complex number. + /// The result of the division. + /// The dividend. + /// The divisor. + public static Complex operator /(double dividend, Complex divisor) + { + if (divisor.IsZero) + { + return Infinity; + } + + var zmod = divisor.ModulusSquared; + return new Complex(dividend * divisor._real / zmod, -dividend * divisor._imag / zmod); + } + + /// Division operator. Divides a complex number by a double value. + /// The result of the division. + /// The dividend. + /// The divisor. + public static Complex operator /(Complex dividend, double divisor) + { + if (divisor.AlmostZero()) + { + return Infinity; + } + + return new Complex(dividend._real / divisor, dividend._imag / divisor); + } + + /// + /// Implicit conversion of a real double to a real Complex. + /// + /// The double value to convert. + /// The result of the conversion. + public static implicit operator Complex(double number) + { + return new Complex(number, 0.0); + } + + /// + /// Unary addition. + /// + /// Returns the same complex number. + public Complex Plus() + { + return this; + } + + /// + /// Unary minus. + /// + /// The negated value of this complex number. + public Complex Negate() + { + return -this; + } + + /// Adds a complex number to this one. + /// The result of the addition. + /// The other complex number to add. + public Complex Add(Complex other) + { + return this + other; + } + + /// Subtracts a complex number from this one. + /// The result of the subtraction. + /// The other complex number to subtract from this one. + public Complex Subtract(Complex other) + { + return this - other; + } + + /// Multiplies this complex number with this one. + /// The result of the multiplication. + /// The complex number to multiply. + public Complex Multiply(Complex multiplier) + { + return this * multiplier; + } + + /// Divides this complex number by another. + /// The result of the division. + /// The divisor. + public Complex Divide(Complex divisor) + { + return this / divisor; } #endregion diff --git a/src/Managed/SpecialFunctions.cs b/src/Managed/SpecialFunctions.cs index 2f5f5dd2..e00efb83 100644 --- a/src/Managed/SpecialFunctions.cs +++ b/src/Managed/SpecialFunctions.cs @@ -26,6 +26,8 @@ // OTHER DEALINGS IN THE SOFTWARE. // +using System; + namespace MathNet.Numerics { /// @@ -34,5 +36,27 @@ namespace MathNet.Numerics /// public static partial class SpecialFunctions { + /// + /// Computes the hypotenuse of a right angle triangle. + /// + /// The length of side a of the triangle. + /// The length of side b of the triangle. + /// Returns sqrt(a2 + b2) without underflow/overflow. + public static double Hypotenuse(double a, double b) + { + if (Math.Abs(a) > Math.Abs(b)) + { + double r = b / a; + return Math.Abs(a) * Math.Sqrt(1 + r * r); + } + + if (b.AlmostZero()) + { + double r = a / b; + return Math.Abs(b) * Math.Sqrt(1 + r * r); + } + + return 0d; + } } }