// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // namespace MathNet.Numerics { using System; #if !NOSYSNUMERICS using Complex = System.Numerics.Complex; #endif /// /// Double-precision trigonometry toolkit. /// public static class Trig { /// /// Constant to convert a degree to grad. /// private const double DegreeToGradConstant = 10.0 / 9.0; /// /// Converts a degree (360-periodic) angle to a grad (400-periodic) angle. /// /// The degree to convert. /// The converted grad angle. public static double DegreeToGrad(double degree) { return degree * DegreeToGradConstant; } /// /// Converts a degree (360-periodic) angle to a radian (2*Pi-periodic) angle. /// /// The degree to convert. /// The converted radian angle. public static double DegreeToRadian(double degree) { return degree * Constants.Degree; } /// /// Converts a grad (400-periodic) angle to a degree (360-periodic) angle. /// /// The grad to convert. /// The converted degree. public static double GradToDegree(double grad) { return grad * 0.9; } /// /// Converts a grad (400-periodic) angle to a radian (2*Pi-periodic) angle. /// /// The grad to convert. /// The converted radian. public static double GradToRadian(double grad) { return grad * Constants.Grad; } /// /// Converts a radian (2*Pi-periodic) angle to a degree (360-periodic) angle. /// /// The radian to convert. /// The converted degree. public static double RadianToDegree(double radian) { return radian / Constants.Degree; } /// /// Converts a radian (2*Pi-periodic) angle to a grad (400-periodic) angle. /// /// The radian to convert. /// The converted grad. public static double RadianToGrad(double radian) { return radian / Constants.Grad; } /// /// Normalized Sinc function. sinc(x) = sin(pi*x)/(pi*x). /// public static double Sinc(double x) { double z = Math.PI*x; return z.AlmostEqual(0.0, 15) ? 1.0 : Math.Sin(z)/z; } /// /// Trigonometric Sine of an angle in radian, or opposite / hypotenuse. /// /// The angle in radian. /// The sine of the radian angle. public static double Sin(double radian) { return Math.Sin(radian); } /// /// Trigonometric Sine of a Complex number. /// /// The complex value. /// The sine of the complex number. public static Complex Sin(this Complex value) { if (value.IsReal()) { return new Complex(Sin(value.Real), 0.0); } return new Complex( Sin(value.Real) * Cosh(value.Imaginary), Cos(value.Real) * Sinh(value.Imaginary)); } /// /// Trigonometric Cosine of an angle in radian, or adjacent / hypotenuse. /// /// The angle in radian. /// The cosine of an angle in radian. public static double Cos(double radian) { return Math.Cos(radian); } /// /// Trigonometric Cosine of a Complex number. /// /// The complex value. /// The cosine of a complex number. public static Complex Cos(this Complex value) { if (value.IsReal()) { return new Complex(Cos(value.Real), 0.0); } return new Complex( Cos(value.Real) * Cosh(value.Imaginary), -Sin(value.Real) * Sinh(value.Imaginary)); } /// /// Trigonometric Tangent of an angle in radian, or opposite / adjacent. /// /// The angle in radian. /// The tangent of the radian angle. public static double Tan(double radian) { return Math.Tan(radian); } /// /// Trigonometric Tangent of a Complex number. /// /// The complex value. /// The tangent of the complex number. public static Complex Tan(this Complex value) { if (value.IsReal()) { return new Complex(Tan(value.Real), 0.0); } var cosr = Cos(value.Real); var sinhi = Sinh(value.Imaginary); var denom = (cosr * cosr) + (sinhi * sinhi); return new Complex(Sin(value.Real) * cosr / denom, sinhi * Cosh(value.Imaginary) / denom); } /// /// Trigonometric Cotangent of an angle in radian, or adjacent / opposite. Reciprocal of the tangent. /// /// The angle in radian. /// The cotangent of an angle in radian. public static double Cot(double radian) { return 1 / Math.Tan(radian); } /// /// Trigonometric Cotangent of a Complex number. /// /// The complex value. /// The cotangent of the complex number. public static Complex Cot(this Complex value) { if (value.IsReal()) { return new Complex(Cot(value.Real), 0d); } var sinr = Sin(value.Real); var sinhi = Sinh(value.Imaginary); var denom = (sinr * sinr) + (sinhi * sinhi); return new Complex(sinr * Cos(value.Real) / denom, -sinhi * Cosh(value.Imaginary) / denom); } /// /// Trigonometric Secant of an angle in radian, or hypotenuse / adjacent. Reciprocal of the cosine. /// /// The angle in radian. /// The secant of the radian angle. public static double Sec(double radian) { return 1 / Math.Cos(radian); } /// /// Trigonometric Secant of a Complex number. /// /// The complex value. /// The secant of the complex number. public static Complex Sec(this Complex value) { if (value.IsReal()) { return new Complex(Sec(value.Real), 0d); } var cosr = Cos(value.Real); var sinhi = Sinh(value.Imaginary); var denom = (cosr * cosr) + (sinhi * sinhi); return new Complex(cosr * Cosh(value.Imaginary) / denom, Sin(value.Real) * sinhi / denom); } /// /// Trigonometric Cosecant of an angle in radian, or hypotenuse / opposite. Reciprocal of the sine. /// /// The angle in radian. /// Cosecant of an angle in radian. public static double Csc(double radian) { return 1 / Math.Sin(radian); } /// /// Trigonometric Cosecant of a Complex number. /// /// The complex value. /// The cosecant of a complex number. public static Complex Csc(this Complex value) { if (value.IsReal()) { return new Complex(Csc(value.Real), 0d); } var sinr = Sin(value.Real); var sinhi = Sinh(value.Imaginary); var denom = (sinr * sinr) + (sinhi * sinhi); return new Complex(sinr * Cosh(value.Imaginary) / denom, -Cos(value.Real) * sinhi / denom); } /// /// Trigonometric principal Arc Sine in radian /// /// The opposite for a unit hypotenuse (i.e. opposite / hyptenuse). /// The angle in radian. public static double Asin(double opposite) { return Math.Asin(opposite); } /// /// Trigonometric principal Arc Sine of this Complex number. /// /// The complex value. /// The arc sine of a complex number. public static Complex Asin(this Complex value) { if (value.Imaginary > 0 || value.Imaginary == 0d && value.Real < 0) { return -Asin(-value); } return -Complex.ImaginaryOne * ((1 - value.Square()).SquareRoot() + (Complex.ImaginaryOne * value)).Ln(); } /// /// Trigonometric principal Arc Cosine in radian /// /// The adjacent for a unit hypotenuse (i.e. adjacent / hypotenuse). /// The angle in radian. public static double Acos(double adjacent) { return Math.Acos(adjacent); } /// /// Trigonometric principal Arc Cosine of this Complex number. /// /// The complex value. /// The arc cosine of a complex number. public static Complex Acos(this Complex value) { if (value.Imaginary < 0 || value.Imaginary == 0d && value.Real > 0) { return Constants.Pi - Acos(-value); } return -Complex.ImaginaryOne * (value + (Complex.ImaginaryOne * (1 - value.Square()).SquareRoot())).Ln(); } /// /// Trigonometric principal Arc Tangent in radian /// /// The opposite for a unit adjacent (i.e. opposite / adjacent). /// The angle in radian. public static double Atan(double opposite) { return Math.Atan(opposite); } /// /// Trigonometric principal Arc Tangent of this Complex number. /// /// The complex value. /// The arc tangent of a complex number. public static Complex Atan(this Complex value) { var iz = new Complex(-value.Imaginary, value.Real); // I*this return new Complex(0, 0.5) * ((1 - iz).Ln() - (1 + iz).Ln()); } /// /// Trigonometric principal Arc Cotangent in radian /// /// The adjacent for a unit opposite (i.e. adjacent / opposite). /// The angle in radian. public static double Acot(double adjacent) { return Math.Atan(1 / adjacent); } /// /// Trigonometric principal Arc Cotangent of this Complex number. /// /// The complex value. /// The arc cotangent of a complex number. public static Complex Acot(this Complex value) { if (value.IsZero()) { return Constants.PiOver2; } var inv = Complex.ImaginaryOne / value; return (Complex.ImaginaryOne * 0.5) * ((1.0 - inv).Ln() - (1.0 + inv).Ln()); } /// /// Trigonometric principal Arc Secant in radian /// /// The hypotenuse for a unit adjacent (i.e. hypotenuse / adjacent). /// The angle in radian. public static double Asec(double hypotenuse) { return Math.Acos(1 / hypotenuse); } /// /// Trigonometric principal Arc Secant of this Complex number. /// /// The complex value. /// The arc secant of a complex number. public static Complex Asec(this Complex value) { var inv = 1 / value; return -Complex.ImaginaryOne * (inv + (Complex.ImaginaryOne * (1 - inv.Square()).SquareRoot())).Ln(); } /// /// Trigonometric principal Arc Cosecant in radian /// /// The hypotenuse for a unit opposite (i.e. hypotenuse / opposite). /// The angle in radian. public static double Acsc(double hypotenuse) { return Math.Asin(1 / hypotenuse); } /// /// Trigonometric principal Arc Cosecant of this Complex number. /// /// The complex value. /// The arc cosecant of a complex number. public static Complex Acsc(this Complex value) { var inv = 1 / value; return -Complex.ImaginaryOne * ((Complex.ImaginaryOne * inv) + (1 - inv.Square()).SquareRoot()).Ln(); } /// /// Hyperbolic Sine /// /// The hyperbolic angle, i.e. the area of the hyperbolic sector. /// The hyperbolic sine of the angle. public static double Sinh(double angle) { return (Math.Exp(angle) - Math.Exp(-angle)) / 2; } /// /// Hyperbolic Sine of a Complex number. /// /// The complex value. /// The hyperbolic sine of a complex number. public static Complex Sinh(this Complex value) { if (value.IsReal()) { return new Complex(Sinh(value.Real), 0.0); } return new Complex( Sinh(value.Real) * Cos(value.Imaginary), Cosh(value.Real) * Sin(value.Imaginary)); } /// /// Hyperbolic Cosine /// /// The hyperbolic angle, i.e. the area of the hyperbolic sector. /// The hyperbolic Cosine of the angle. public static double Cosh(double angle) { return (Math.Exp(angle) + Math.Exp(-angle)) / 2; } /// /// Hyperbolic Cosine of a Complex number. /// /// The complex value. /// The hyperbolic cosine of a complex number. public static Complex Cosh(this Complex value) { if (value.IsReal()) { return new Complex(Cosh(value.Real), 0.0); } return new Complex( Cosh(value.Real) * Cos(value.Imaginary), Sinh(value.Real) * Sin(value.Imaginary)); } /// /// Hyperbolic Tangent in radian /// /// The hyperbolic angle, i.e. the area of the hyperbolic sector. /// The hyperbolic tangent of the angle. public static double Tanh(double angle) { if (angle > 19.1) { return 1.0; } if (angle < -19.1) { return -1; } var e1 = Math.Exp(angle); var e2 = Math.Exp(-angle); return (e1 - e2) / (e1 + e2); } /// /// Hyperbolic Tangent of a Complex number. /// /// The complex value. /// The hyperbolic tangent of a complex number. public static Complex Tanh(this Complex value) { if (value.IsReal()) { return new Complex(Tanh(value.Real), 0.0); } var cosi = Cos(value.Imaginary); var sinhr = Sinh(value.Real); if (double.IsInfinity(sinhr)) { return new Complex(double.IsPositiveInfinity(sinhr) ? 1 : -1, 0.0); } var denom = (cosi * cosi) + (sinhr * sinhr); return new Complex(Cosh(value.Real) * sinhr / denom, cosi * Sin(value.Imaginary) / denom); } /// /// Hyperbolic Cotangent /// /// The hyperbolic angle, i.e. the area of the hyperbolic sector. /// The hyperbolic cotangent of the angle. public static double Coth(double angle) { if (angle > 19.115) { return 1.0; } if (angle < -19.115) { return -1; } var e1 = Math.Exp(angle); var e2 = Math.Exp(-angle); return (e1 + e2) / (e1 - e2); } /// /// Hyperbolic Cotangent of a Complex number. /// /// The complex value. /// The hyperbolic cotangent of a complex number. public static Complex Coth(this Complex value) { if (value.IsReal()) { return new Complex(Coth(value.Real), 0.0); } var sini = Sin(value.Imaginary); var sinhr = Sinh(value.Real); if (double.IsInfinity(sinhr)) { return new Complex(double.IsPositiveInfinity(sinhr) ? 1 : -1, 0.0); } var denom = (sini * sini) + (sinhr * sinhr); return new Complex(sinhr * Cosh(value.Real) / denom, sini * Cos(value.Imaginary) / denom); } /// /// Hyperbolic Secant /// /// The hyperbolic angle, i.e. the area of the hyperbolic sector. /// The hyperbolic secant of the angle. public static double Sech(double angle) { return 1 / Cosh(angle); } /// /// Hyperbolic Secant of a Complex number. /// /// The complex value. /// The hyperbolic secant of a complex number. public static Complex Sech(this Complex value) { if (value.IsReal()) { return new Complex(Sech(value.Real), 0.0); } var exp = value.Exp(); if (exp.IsInfinity()) { return Complex.Zero; } return 2 * exp / (exp.Square() + 1); } /// /// Hyperbolic Cosecant /// /// The hyperbolic angle, i.e. the area of the hyperbolic sector. /// The hyperbolic cosecant of the angle. public static double Csch(double angle) { return 1 / Sinh(angle); } /// /// Hyperbolic Cosecant of a Complex number. /// /// The complex value. /// The hyperbolic cosecant of a complex number. public static Complex Csch(this Complex value) { if (value.IsReal()) { return new Complex(Csch(value.Real), 0.0); } var exp = value.Exp(); if (exp.IsInfinity()) { return Complex.Zero; } return 2 * exp / (exp.Square() - 1); } /// /// Hyperbolic Area Sine /// /// The real value. /// The hyperbolic angle, i.e. the area of its hyperbolic sector. public static double Asinh(double value) { return Math.Log(value + Math.Sqrt((value * value) + 1), Math.E); } /// /// Hyperbolic Area Sine of this Complex number. /// /// The complex value. /// The hyperbolic arc sine of a complex number. public static Complex Asinh(this Complex value) { return (value + (value.Square() + 1).SquareRoot()).Ln(); } /// /// Hyperbolic Area Cosine /// /// The real value. /// The hyperbolic angle, i.e. the area of its hyperbolic sector. public static double Acosh(double value) { return Math.Log(value + (Math.Sqrt(value - 1) * Math.Sqrt(value + 1)), Math.E); } /// /// Hyperbolic Area Cosine of this Complex number. /// /// The complex value. /// The hyperbolic arc cosine of a complex number. public static Complex Acosh(this Complex value) { return (value + ((value - 1).SquareRoot() * (value + 1).SquareRoot())).Ln(); } /// /// Hyperbolic Area Tangent /// /// The real value. /// The hyperbolic angle, i.e. the area of its hyperbolic sector. public static double Atanh(double value) { return 0.5 * Math.Log((1 + value) / (1 - value), Math.E); } /// /// Hyperbolic Area Tangent of this Complex number. /// /// The complex value. /// The hyperbolic arc tangent of a complex number. public static Complex Atanh(this Complex value) { return 0.5 * ((1 + value).Ln() - (1 - value).Ln()); } /// /// Hyperbolic Area Cotangent /// /// The real value. /// The hyperbolic angle, i.e. the area of its hyperbolic sector. public static double Acoth(double value) { return 0.5 * Math.Log((value + 1) / (value - 1), Math.E); } /// /// Hyperbolic Area Cotangent of this Complex number. /// /// The complex value. /// The hyperbolic arc cotangent of a complex number. public static Complex Acoth(this Complex value) { var inv = 1.0 / value; return 0.5 * ((1.0 + inv).Ln() - (1.0 - inv).Ln()); } /// /// Hyperbolic Area Secant /// /// The real value. /// The hyperbolic angle, i.e. the area of its hyperbolic sector. public static double Asech(double value) { return Acosh(1 / value); } /// /// Hyperbolic Area Secant of this Complex number. /// /// The complex value. /// The hyperbolic arc secant of a complex number. public static Complex Asech(this Complex value) { var inv = 1 / value; return (inv + ((inv - 1).SquareRoot() * (inv + 1).SquareRoot())).Ln(); } /// /// Hyperbolic Area Cosecant /// /// The real value. /// The hyperbolic angle, i.e. the area of its hyperbolic sector. public static double Acsch(double value) { return Asinh(1 / value); } /// /// Hyperbolic Area Cosecant of this Complex number. /// /// The complex value. /// The hyperbolic arc cosecant of a complex number. public static Complex Acsch(this Complex value) { var inv = 1 / value; return (inv + (inv.Square() + 1).SquareRoot()).Ln(); } } }