diff --git a/MathTrigonometric.Tests/MathTrigTests.ComplexNumbers.cs b/MathTrigonometric.Tests/MathTrigTests.ComplexNumbers.cs new file mode 100644 index 0000000..20ccf12 --- /dev/null +++ b/MathTrigonometric.Tests/MathTrigTests.ComplexNumbers.cs @@ -0,0 +1,657 @@ +using System.Numerics; + +namespace MathTrigonometric.Tests; + +public partial class MathTrigTests +{ + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.Epsilon, 0d)] + [InlineData(-Math.PI / 2, 0d, -1d, 0)] + [InlineData(-Math.PI / 3, 0d, -0.8660254037844386d, 0d)] + [InlineData(-Math.PI / 4, 0d, -0.70710678118654757d, 0d)] + [InlineData(-Math.PI / 6, 0d, -0.49999999999999994d, 0d)] + [InlineData(0d, 0d, 0d, 0d)] + [InlineData(1d, 0d, 0.8414709848078965d, 0d)] + [InlineData(Math.PI / 6, 0d, 0.49999999999999994d, 0d)] + [InlineData(Math.PI / 4, 0d, 0.70710678118654757d, 0d)] + [InlineData(Math.PI / 3, 0d, 0.8660254037844386d, 0d)] + [InlineData(Math.PI / 2, 0d, 1d, 0d)] + [InlineData(-Math.PI, 0d, -1.2246467991473532E-16d, 0d)] + [InlineData(Math.PI, 0d, 1.2246467991473532E-16d, 0d)] + [InlineData(double.PositiveInfinity, 0d, double.NaN, double.NaN)] + [InlineData(double.NegativeInfinity, 0d, double.NaN, double.NaN)] + [InlineData(2d, 3d, 9.15449914691143d, -4.168906959966565d)] + [InlineData(2d, -3d, 9.15449914691143d, 4.168906959966565d)] + [InlineData(-2d, 3d, -9.15449914691143d, -4.168906959966565d)] + [InlineData(-2d, -3d, -9.15449914691143d, 4.168906959966565d)] + //[InlineData(0.01, 711.0, 3.0E+306, double.PositiveInfinity)] + public void MathTrig_SinComplexNumbers_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Sin(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, 1d)] + [InlineData(-Math.PI / 2, 0d, 6.123233995736766E-17d)] + [InlineData(-Math.PI / 3, 0d, 0.50000000000000011d)] + [InlineData(-Math.PI / 4, 0d, 0.70710678118654757d)] + [InlineData(-Math.PI / 6, 0d, 0.86602540378443871d)] + [InlineData(0d, 0d, 1d)] + [InlineData(1d, 0d, 0.54030230586813977d)] + [InlineData(Math.PI / 6, 0d, 0.86602540378443871d, 0d)] + [InlineData(Math.PI / 4, 0d, 0.70710678118654757d, 0d)] + [InlineData(Math.PI / 3, 0d, 0.50000000000000011d, 0d)] + [InlineData(Math.PI / 2, 0d, 6.123233995736766E-17d, 0d)] + [InlineData(-Math.PI, 0d, -1d)] + [InlineData(Math.PI, 0d, -1d)] + [InlineData(double.PositiveInfinity, 0d, double.NaN, double.NaN)] + [InlineData(double.NegativeInfinity, 0d, double.NaN, double.NaN)] + [InlineData(2d, 3d, -4.189625690968807d, -9.109227893755337d)] + [InlineData(2d, -3d, -4.189625690968807d, 9.109227893755337d)] + [InlineData(-2d, 3d, -4.189625690968807d, 9.109227893755337d)] + [InlineData(-2d, -3d, -4.189625690968807d, -9.109227893755337d)] + public void MathTrig_CosComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Cos(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.Epsilon)] + [InlineData(-Math.PI / 2, 0d, double.NegativeInfinity, double.NaN)] + [InlineData(-Math.PI / 3, 0d, -1.7320508075688767d)] + [InlineData(-Math.PI / 4, 0d, -1d)] + [InlineData(-Math.PI / 6, 0d, -0.5773502691896257d)] + [InlineData(0d, 0d, 0d)] + [InlineData(1d, 0d, 1.5574077246549021d)] + [InlineData(Math.PI / 6, 0d, 0.5773502691896257d, 0d)] + [InlineData(Math.PI / 4, 0d, 1d, 0d)] + [InlineData(Math.PI / 3, 0d, 1.7320508075688767d, 0d)] + [InlineData(Math.PI / 2, 0d, double.PositiveInfinity, double.NaN)] + [InlineData(-Math.PI, 0d, -1.2246467991473532E-16d / -1d)] + [InlineData(Math.PI, 0d, 1.2246467991473532E-16d / -1d)] + [InlineData(double.PositiveInfinity, 0d, double.NaN, double.NaN)] + [InlineData(double.NegativeInfinity, 0d, double.NaN, double.NaN)] + [InlineData(2d, 3d, -0.0037640256415042484, 1.0032386273536098)] + [InlineData(2d, -3d, -0.0037640256415042484, -1.0032386273536098)] + [InlineData(-2d, 3d, 0.0037640256415042484, 1.0032386273536098)] + [InlineData(-2d, -3d, 0.0037640256415042484, -1.0032386273536098)] + public void MathTrig_TanComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Tan(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.PositiveInfinity)] + [InlineData(-Math.PI / 2, 0d, -1d)] + [InlineData(-Math.PI / 3, 0d, 1 / -0.8660254037844386d)] + [InlineData(-Math.PI / 4, 0d, 1 / -0.70710678118654757d)] + [InlineData(-Math.PI / 6, 0d, 1 / -0.49999999999999994d)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(Math.PI / 6, 0d, 1 / 0.49999999999999994d)] + [InlineData(Math.PI / 4, 0d, 1 / 0.70710678118654757d)] + [InlineData(Math.PI / 3, 0d, 1 / 0.8660254037844386d)] + [InlineData(Math.PI / 2, 0d, 1d, 0d)] + [InlineData(-Math.PI, 0d, 1 / -1.2246467991473532E-16d)] + [InlineData(Math.PI, 0d, 1 / 1.2246467991473532E-16d)] + [InlineData(Math.PI + Math.PI / 2, 0d, -1d)] + [InlineData(-Math.PI - Math.PI / 2, 0d, 1d)] + [InlineData(double.PositiveInfinity, 0d, double.NaN, double.NaN)] + [InlineData(double.NegativeInfinity, 0d, double.NaN, double.NaN)] + [InlineData(2d, 3d, 0.09047320975320743, 0.041200986288574125)] + [InlineData(2d, -3d, 0.09047320975320743, -0.041200986288574125)] + [InlineData(-2d, 3d, -0.09047320975320743, 0.041200986288574125)] + [InlineData(-2d, -3d, -0.09047320975320743, -0.041200986288574125)] + public void MathTrig_CscComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Csc(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, 1d)] + [InlineData(-Math.PI / 2, 0d, 1 / 6.123233995736766E-17d)] + [InlineData(-Math.PI / 3, 0d, 1 / 0.50000000000000011d)] + [InlineData(-Math.PI / 4, 0d, 1 / 0.70710678118654757d)] + [InlineData(-Math.PI / 6, 0d, 1 / 0.86602540378443871d)] + [InlineData(0d, 0d, 1d)] + [InlineData(Math.PI / 6, 0d, 1 / 0.86602540378443871d)] + [InlineData(Math.PI / 4, 0d, 1 / 0.70710678118654757d)] + [InlineData(Math.PI / 3, 0d, 1 / 0.50000000000000011d)] + [InlineData(Math.PI / 2, 0d, 1 / 6.123233995736766E-17d)] + [InlineData(-Math.PI, 0d, -1d)] + [InlineData(Math.PI, 0d, -1d)] + [InlineData(-2 * Math.PI, 0d, 1d)] + [InlineData(2 * Math.PI, 0d, 1d)] + [InlineData(double.PositiveInfinity, 0d, double.NaN, double.NaN)] + [InlineData(double.NegativeInfinity, 0d, double.NaN, double.NaN)] + [InlineData(2d, 3d, -0.041674964411144266, 0.0906111371962376)] + [InlineData(2d, -3d, -0.041674964411144266, -0.0906111371962376)] + [InlineData(-2d, 3d, -0.041674964411144266, -0.0906111371962376)] + [InlineData(-2d, -3d, -0.041674964411144266, 0.0906111371962376)] + public void MathTrig_SecComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Sec(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.PositiveInfinity)] + [InlineData(-Math.PI / 2, 0d, -1 / 16331239353195370d)] + [InlineData(-Math.PI / 3, 0d, -1 / 1.7320508075688767d)] + [InlineData(-Math.PI / 4, 0d, -1d)] + [InlineData(-Math.PI / 6, 0d, -1 / 0.57735026918962562d)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(Math.PI / 6, 0d, 1 / 0.57735026918962562d)] + [InlineData(Math.PI / 4, 0d, 1d, 0d)] + [InlineData(Math.PI / 3, 0d, 1 / 1.7320508075688767d)] + [InlineData(Math.PI / 2, 0d, 1 / 16331239353195370d)] + [InlineData(-Math.PI, 0d, -1d / -1.2246467991473532E-16d)] + [InlineData(Math.PI, 0d, -1d / 1.2246467991473532E-16d)] + [InlineData(double.PositiveInfinity, 0d, double.NaN, double.NaN)] + [InlineData(double.NegativeInfinity, 0d, double.NaN, double.NaN)] + [InlineData(2d, 3d, -0.003739710376336932, -0.9967577965693583)] + [InlineData(2d, -3d, -0.003739710376336932, 0.9967577965693583)] + [InlineData(-2d, 3d, 0.003739710376336932, -0.9967577965693583)] + [InlineData(-2d, -3d, 0.003739710376336932, 0.9967577965693583)] + public void MathTrig_CotComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Cot(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d)] + [InlineData(double.Epsilon, 0d, double.Epsilon)] + [InlineData(0.5d, 0d, 0.52359877559829893d)] //PI / 6 + [InlineData(1d, 0d, Math.PI / 2)] + [InlineData(2d, 0d, Math.PI / 2, 1.3169578969248166d)] + [InlineData(double.PositiveInfinity, 0d, Math.PI / 2, double.PositiveInfinity)] + [InlineData(-0.5d, 0d, -0.52359877559829893d)] //PI / 6 + [InlineData(-1d, 0d, -Math.PI / 2, 0d)] + [InlineData(-2d, 0d, -Math.PI / 2, 1.3169578969248166d)] + [InlineData(double.NegativeInfinity, 0d, -Math.PI / 2, double.PositiveInfinity)] + [InlineData(2d, 3d, 0.5706527843210993, 1.9833870299165357)] + [InlineData(2d, -3d, 0.5706527843210993, -1.9833870299165357)] + [InlineData(-2d, 3d, -0.5706527843210993, 1.9833870299165357)] + [InlineData(-2d, -3d, -0.5706527843210993, -1.9833870299165357)] + public void MathTrig_AsinComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Asin(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, Math.PI / 2)] + [InlineData(double.Epsilon, 0d, Math.PI / 2 - double.Epsilon)] + [InlineData(0.5d, 0d, 1.0471975511965979d)] //PI / 3 + [InlineData(1d, 0d, 0d)] + [InlineData(2d, 0d, 0d, 1.3169578969248166d)] + [InlineData(double.PositiveInfinity, 0d, 0d, double.PositiveInfinity)] + [InlineData(-0.5d, 0d, Math.PI * 2 / 3)] + [InlineData(-1d, 0d, Math.PI)] + [InlineData(-2d, 0d, Math.PI, 1.3169578969248166d)] + [InlineData(double.NegativeInfinity, 0d, Math.PI, double.PositiveInfinity)] + [InlineData(2d, 3d, 1.0001435424737972, -1.9833870299165357)] + [InlineData(2d, -3d, 1.0001435424737972, 1.9833870299165357)] + [InlineData(-2d, 3d, 2.141449111115996, -1.9833870299165357)] + [InlineData(-2d, -3d, 2.141449111115996, 1.9833870299165357)] + public void MathTrig_AcosComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Acos(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d)] + [InlineData(double.Epsilon, 0d, double.Epsilon)] + [InlineData(0.5d, 0d, 0.46364760900080609d)] + [InlineData(1d, 0d, Math.PI / 4)] + [InlineData(2d, 0d, 1.1071487177940904d)] + [InlineData(double.PositiveInfinity, 0d, Math.PI / 2)] + [InlineData(-0.5d, 0d, -0.46364760900080609d)] + [InlineData(-1d, 0d, -Math.PI / 4)] + [InlineData(-2d, 0d, -1.1071487177940904d)] + [InlineData(double.NegativeInfinity, 0d, -Math.PI / 2)] + [InlineData(2d, 3d, 1.4099210495965755, 0.22907268296853878)] + [InlineData(2d, -3d, 1.4099210495965755, -0.22907268296853878)] + [InlineData(-2d, 3d, -1.4099210495965755, 0.22907268296853878)] + [InlineData(-2d, -3d, -1.4099210495965755, -0.22907268296853878)] + public void MathTrig_AtanComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Atan(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, Math.PI / 2, double.PositiveInfinity)] + [InlineData(double.Epsilon * 10000000000000000, 0d, Math.PI / 2, 708.2918576140364d)] + [InlineData(-double.Epsilon, 0d, -Math.PI / 2, double.PositiveInfinity)] + [InlineData(0.5d, 0d, Math.PI / 2, 1.3169578969248166d)] + [InlineData(1d, 0d, Math.PI / 2)] + [InlineData(2d, 0d, 0.52359877559829893d)] //PI / 6 + [InlineData(double.PositiveInfinity, 0d, 0d)] + [InlineData(-0.5d, 0d, -Math.PI / 2, 1.3169578969248166d)] + [InlineData(-1d, 0d, -Math.PI / 2)] + [InlineData(-2d, 0d, -0.52359877559829893d)] //PI / 6 + [InlineData(double.NegativeInfinity, 0d, 0d)] + [InlineData(2d, 3d, 0.150385604327862, -0.23133469857397337)] + [InlineData(2d, -3d, 0.150385604327862, 0.23133469857397337)] + [InlineData(-2d, 3d, -0.150385604327862, -0.23133469857397337)] + [InlineData(-2d, -3d, -0.150385604327862, 0.23133469857397337)] + public void MathTrig_AcscComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Acsc(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, 0d, double.PositiveInfinity)] + [InlineData(0.5d, 0d, 0d, 1.3169578969248166d)] + [InlineData(1d, 0d, 0d)] + [InlineData(2d, 0d, 1.0471975511965979d)] //PI / 3 + [InlineData(double.PositiveInfinity, 0d, Math.PI / 2)] + [InlineData(-0.5d, 0d, Math.PI, 1.3169578969248166d)] + [InlineData(-1d, 0d, Math.PI)] + [InlineData(-2d, 0d, Math.PI * 2 / 3)] + [InlineData(double.NegativeInfinity, 0d, Math.PI / 2)] + [InlineData(2d, 3d, 1.4204107224670346, 0.23133469857397337)] + [InlineData(2d, -3d, 1.4204107224670346, -0.23133469857397337)] + [InlineData(-2d, 3d, 1.7211819311227585, 0.23133469857397337)] + [InlineData(-2d, -3d, 1.7211819311227585, -0.23133469857397337)] + public void MathTrig_AsecComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Asec(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, Math.PI / 2)] + [InlineData(double.Epsilon, 0d, Math.PI / 2 - double.Epsilon)] + [InlineData(1E-10, 0d, 1.5707963266948965d, 0)] + [InlineData(-1E-10, 0d, Math.PI - 1.5707963266948965d, 0)] + [InlineData(-double.Epsilon, 0d, Math.PI / 2 - double.Epsilon)] + [InlineData(0.5d, 0d, 1.1071487177940904d)] + [InlineData(1d, 0d, Math.PI / 4)] + [InlineData(2d, 0d, 0.46364760900080609d)] + [InlineData(double.PositiveInfinity, 0d, 0d)] + [InlineData(-0.5d, 0d, Math.PI - 1.1071487177940904d)] + [InlineData(-1d, 0d, Math.PI - Math.PI / 4)] + [InlineData(-2d, 0d, Math.PI - 0.46364760900080609d)] + [InlineData(double.NegativeInfinity, 0d, Math.PI)] + [InlineData(2d, 3d, 0.16087527719832112, -0.22907268296853883)] + [InlineData(2d, -3d, 0.16087527719832112, 0.22907268296853883)] + [InlineData(-2d, 3d, 2.980717376391472, -0.22907268296853883)] + [InlineData(-2d, -3d, 2.980717376391472, 0.22907268296853883)] + public void MathTrig_AcotComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Acot(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d)] + [InlineData(double.Epsilon, 0d, double.Epsilon)] + [InlineData(1E-10, 0d, 1E-10)] + [InlineData(-1E-10, 0d, -1E-10)] + [InlineData(0.5d, 0d, 0.52109530549374738d)] + [InlineData(1d, 0d, 1.1752011936438014d)] + [InlineData(2d, 0d, 3.6268604078470186d)] + [InlineData(10, 0d, 11013.232874703393, 0d)] + [InlineData(100, 0d, 1.3440585709080678E+43d, 0d)] + [InlineData(double.PositiveInfinity, 0d, double.PositiveInfinity)] + [InlineData(-0.5d, 0d, -0.52109530549374738d)] + [InlineData(-1d, 0d, -1.1752011936438014d)] + [InlineData(-2d, 0d, -3.6268604078470186d)] + [InlineData(double.NegativeInfinity, 0d, double.NegativeInfinity)] + [InlineData(2d, 3d, -3.5905645899857794d, 0.5309210862485197d)] + [InlineData(2d, -3d, -3.5905645899857794d, -0.5309210862485197d)] + [InlineData(-2d, 3d, 3.5905645899857794d, 0.5309210862485197d)] + [InlineData(-2d, -3d, 3.5905645899857794d, -0.5309210862485197d)] + public void MathTrig_SinhComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Sinh(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 1d)] + [InlineData(double.Epsilon, 0d, 1d)] + [InlineData(0.5d, 0d, 1.1276259652063807d)] + [InlineData(1d, 0d, 1.5430806348152437d)] + [InlineData(2d, 0d, 3.7621956910836314d)] + [InlineData(double.PositiveInfinity, 0d, double.PositiveInfinity)] + [InlineData(-0.5d, 0d, 1.1276259652063807d)] + [InlineData(-1d, 0d, 1.5430806348152437d)] + [InlineData(-2d, 0d, 3.7621956910836314d)] + [InlineData(double.NegativeInfinity, 0d, double.PositiveInfinity)] + [InlineData(2d, 3d, -3.7245455049153224, 0.5118225699873845)] + [InlineData(2d, -3d, -3.7245455049153224, -0.5118225699873845)] + [InlineData(-2d, 3d, -3.7245455049153224, -0.5118225699873845)] + [InlineData(-2d, -3d, -3.7245455049153224, 0.5118225699873845)] + public void MathTrig_CoshComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Cosh(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d)] + [InlineData(double.Epsilon, 0d, double.Epsilon)] + [InlineData(0.5d, 0d, 0.46211715726000974d)] + [InlineData(1d, 0d, 0.76159415595576485d)] + [InlineData(2d, 0d, 0.9640275800758169d)] + [InlineData(double.PositiveInfinity, 0d, 1d)] + [InlineData(-0.5d, 0d, -0.46211715726000974d)] + [InlineData(-1d, 0d, -0.76159415595576485d)] + [InlineData(-2d, 0d, -0.9640275800758169d)] + [InlineData(double.NegativeInfinity, 0d, -1d)] + [InlineData(2d, 3d, 0.9653858790221331, -0.009884375038322494)] + [InlineData(2d, -3d, 0.9653858790221331, 0.009884375038322494)] + [InlineData(-2d, 3d, -0.9653858790221331, -0.009884375038322494)] + [InlineData(-2d, -3d, -0.9653858790221331, 0.009884375038322494)] + public void MathTrig_TanhComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Tanh(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.PositiveInfinity)] + [InlineData(0.5d, 0d, 1 / 0.52109530549374738d)] + [InlineData(1d, 0d, 1 / 1.1752011936438014d)] + [InlineData(2d, 0d, 1 / 3.6268604078470186d)] + [InlineData(double.PositiveInfinity, 0d, 0d)] + [InlineData(-0.5d, 0d, 1 / -0.52109530549374738d)] + [InlineData(-1d, 0d, 1 / -1.1752011936438014d)] + [InlineData(-2d, 0d, 1 / -3.6268604078470186d)] + [InlineData(double.NegativeInfinity, 0d, 0d)] + [InlineData(2d, 3d, -0.2725486614629402, -0.04030057885689153)] + [InlineData(2d, -3d, -0.2725486614629402, 0.04030057885689153)] + [InlineData(-2d, 3d, 0.2725486614629402, -0.04030057885689153)] + [InlineData(-2d, -3d, 0.2725486614629402, 0.04030057885689153)] + public void MathTrig_CschComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Csch(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 1d)] + [InlineData(double.Epsilon, 0d, 1d)] + [InlineData(0.5d, 0d, 1 / 1.1276259652063807d)] + [InlineData(1d, 0d, 1 / 1.5430806348152437d)] + [InlineData(2d, 0d, 1 / 3.7621956910836314d)] + [InlineData(double.PositiveInfinity, 0d, 0d)] + [InlineData(-0.5d, 0d, 1 / 1.1276259652063807d)] + [InlineData(-1d, 0d, 1 / 1.5430806348152437d)] + [InlineData(-2d, 0d, 1 / 3.7621956910836314d)] + [InlineData(double.NegativeInfinity, 0d, 0d)] + [InlineData(2d, 3d, -0.2635129751583893, -0.036211636558768516)] + [InlineData(2d, -3d, -0.2635129751583893, 0.036211636558768516)] + [InlineData(-2d, 3d, -0.2635129751583893, 0.036211636558768516)] + [InlineData(-2d, -3d, -0.2635129751583893, -0.036211636558768516)] + public void MathTrig_SechComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Sech(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.PositiveInfinity)] + [InlineData(0.5d, 0d, 1 / 0.46211715726000974d)] + [InlineData(1d, 0d, 1 / 0.76159415595576485d)] + [InlineData(2d, 0d, 1 / 0.9640275800758169d)] + [InlineData(double.PositiveInfinity, 0d, 1d)] + [InlineData(-0.5d, 0d, 1 / -0.46211715726000974d)] + [InlineData(-1d, 0d, 1 / -0.76159415595576485d)] + [InlineData(-2d, 0d, 1 / -0.9640275800758169d)] + [InlineData(double.NegativeInfinity, 0d, -1d)] + [InlineData(2d, 3d, 1.0357466377649955, 0.0106047834703371)] + [InlineData(2d, -3d, 1.0357466377649955, -0.0106047834703371)] + [InlineData(-2d, 3d, -1.0357466377649955, 0.0106047834703371)] + [InlineData(-2d, -3d, -1.0357466377649955, -0.0106047834703371)] + public void MathTrig_CothComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Coth(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d)] + [InlineData(double.Epsilon, 0d, 0d)] + [InlineData(0.5d, 0d, 0.48121182505960347d)] + [InlineData(1d, 0d, 0.88137358701954294d)] + [InlineData(2d, 0d, 1.4436354751788103d)] + [InlineData(double.PositiveInfinity, 0d, double.PositiveInfinity)] + [InlineData(-0.5d, 0d, -0.48121182505960347d)] + [InlineData(-1d, 0d, -0.88137358701954294d)] + [InlineData(-2d, 0d, -1.4436354751788103d)] + [InlineData(double.NegativeInfinity, 0d, double.NegativeInfinity)] + [InlineData(double.MinValue, 0d, double.NegativeInfinity)] + [InlineData(double.MaxValue, 0d, double.PositiveInfinity)] + [InlineData(2d, 3d, 1.9686379257930964, 0.9646585044076028)] + [InlineData(2d, -3d, 1.9686379257930964, -0.9646585044076028)] + [InlineData(-2d, 3d, -1.9686379257930964, 0.9646585044076028)] + [InlineData(-2d, -3d, -1.9686379257930964, -0.9646585044076028)] + public void MathTrig_AsinhComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Asinh(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d, Math.PI / 2)] + [InlineData(double.Epsilon, 0d, 0d, Math.PI / 2)] + [InlineData(0.5d, 0d, 0d, Math.PI / 3)] + [InlineData(1d, 0d, 0d)] + [InlineData(2d, 0d, 1.3169578969248166d)] + [InlineData(double.PositiveInfinity, 0d, double.PositiveInfinity)] + [InlineData(-0.5d, 0d, 0d, 2.0943951023931957d)] + [InlineData(-1d, 0d, 0d, Math.PI)] + [InlineData(-2d, 0d, -1.3169578969248164d, Math.PI)] + [InlineData(double.NegativeInfinity, 0d, double.PositiveInfinity)] + [InlineData(double.MinValue, 0d, double.PositiveInfinity)] + [InlineData(double.MaxValue, 0d, double.PositiveInfinity)] + [InlineData(2d, 3d, 1.9833870299165355, 1.0001435424737972)] + [InlineData(2d, -3d, 1.9833870299165355, -1.0001435424737972)] + [InlineData(-2d, 3d, -1.9833870299165355, -2.1414491111159957)] + [InlineData(-2d, -3d, -1.9833870299165355, 2.1414491111159957)] + public void MathTrig_AcoshComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Acosh(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d)] + [InlineData(double.Epsilon, 0d, 0d)] + [InlineData(0.5d, 0d, 0.54930614433405489d)] + [InlineData(1d, 0d, double.PositiveInfinity)] + [InlineData(2d, 0d, 0.5493061443340549, -Math.PI / 2)] + [InlineData(double.PositiveInfinity, 0d, 0d, -Math.PI / 2)] + [InlineData(-0.5d, 0d, -0.54930614433405489d)] + [InlineData(-1d, 0d, double.NegativeInfinity)] + [InlineData(-2d, 0d, -0.5493061443340549, Math.PI / 2)] + [InlineData(double.NegativeInfinity, 0d, 0d, Math.PI / 2)] + [InlineData(double.MinValue, 0d, 0d, Math.PI / 2)] + [InlineData(double.MaxValue, 0d, 0d, -Math.PI / 2)] + [InlineData(2d, 3d, 0.14694666622552977, 1.3389725222944935)] + [InlineData(2d, -3d, 0.14694666622552977, -1.3389725222944935)] + [InlineData(-2d, 3d, -0.14694666622552977, 1.3389725222944935)] + [InlineData(-2d, -3d, -0.14694666622552977, -1.3389725222944935)] + public void MathTrig_AtanhComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Atanh(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.PositiveInfinity)] + [InlineData(-double.Epsilon, 0d, double.NegativeInfinity)] + [InlineData(0.5d, 0d, 1.4436354751788103d)] + [InlineData(1d, 0d, 0.88137358701954294d)] + [InlineData(2d, 0d, 0.48121182505960347d)] + [InlineData(double.PositiveInfinity, 0d, 0d)] + [InlineData(-0.5d, 0d, -1.4436354751788103d)] + [InlineData(-1d, 0d, -0.88137358701954294d)] + [InlineData(-2d, 0d, -0.48121182505960347d)] + [InlineData(double.NegativeInfinity, 0d, 0d)] + [InlineData(2d, 3d, 0.15735549884498526, -0.22996290237720785)] + [InlineData(2d, -3d, 0.15735549884498526, 0.22996290237720785)] + [InlineData(-2d, 3d, -0.15735549884498526, -0.22996290237720785)] + [InlineData(-2d, -3d, -0.15735549884498526, 0.22996290237720785)] + public void MathTrig_AcschComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Acsch(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, double.NaN, double.NaN)] + [InlineData(double.Epsilon, 0d, double.PositiveInfinity)] + [InlineData(-double.Epsilon, 0d, double.PositiveInfinity, Math.PI)] + [InlineData(0.5d, 0d, 1.3169578969248166d)] + [InlineData(1d, 0d, 0d)] + [InlineData(2d, 0d, 0d, Math.PI / 3)] + [InlineData(double.PositiveInfinity, 0d, 0d, Math.PI / 2)] + [InlineData(-0.5d, 0d, -1.3169578969248164d, Math.PI)] + [InlineData(-1d, 0d, 0d, Math.PI)] + [InlineData(-2d, 0d, 0d, 2.0943951023931957d)] //2PI / 3 + [InlineData(double.NegativeInfinity, 0d, 0d, Math.PI / 2)] + [InlineData(double.MinValue, 0d, 0d, Math.PI / 2)] + [InlineData(double.MaxValue, 0d, 0d, Math.PI / 2)] + [InlineData(2d, 3d, 0.23133469857397337, -1.4204107224670346)] + [InlineData(2d, -3d, 0.23133469857397337, 1.4204107224670346)] + [InlineData(-2d, 3d, -0.23133469857397346, 1.7211819311227585)] + [InlineData(-2d, -3d, -0.23133469857397346, -1.7211819311227585)] + public void MathTrig_AsechComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Asech(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } + + [Theory] + [InlineData(double.NaN, 0d, double.NaN, double.NaN)] + [InlineData(0d, 0d, 0d, -Math.PI / 2)] + [InlineData(double.Epsilon, 0d, 0d, -Math.PI / 2)] + [InlineData(0.5d, 0d, 0.5493061443340549, -Math.PI / 2)] + [InlineData(1d, 0d, double.PositiveInfinity)] + [InlineData(2d, 0d, 0.54930614433405489d)] + [InlineData(double.PositiveInfinity, 0d, 0d)] + [InlineData(-0.5d, 0d, -0.5493061443340549, -Math.PI / 2)] + [InlineData(-1d, 0d, double.NegativeInfinity)] + [InlineData(-2d, 0d, -0.54930614433405489d)] + [InlineData(double.NegativeInfinity, 0d, 0d)] + [InlineData(2d, 3d, 0.14694666622552977, -0.23182380450040305)] + [InlineData(2d, -3d, 0.14694666622552977, 0.23182380450040305)] + [InlineData(-2d, 3d, -0.14694666622552977, -0.23182380450040305)] + [InlineData(-2d, -3d, -0.14694666622552977, 0.23182380450040305)] + public void MathTrig_AcothComplexParam_ExpectedValue(double a, double b, double expectedReal, double expectedImaginary = 0) + { + var expectedValue = new Complex(expectedReal, expectedImaginary); + + var value = MathTrig.Acoth(new Complex(a, b)); + + Assert.Equal(expectedValue, value); + } +} \ No newline at end of file diff --git a/MathTrigonometric.Tests/MathTrigTests.cs b/MathTrigonometric.Tests/MathTrigTests.cs index 76ac296..c639227 100644 --- a/MathTrigonometric.Tests/MathTrigTests.cs +++ b/MathTrigonometric.Tests/MathTrigTests.cs @@ -1,6 +1,6 @@ namespace MathTrigonometric.Tests; -public class MathTrigTests +public partial class MathTrigTests { [Theory] [InlineData(double.NaN, double.NaN)] @@ -258,8 +258,6 @@ public void MathTrig_Acot_ExpectedValue(double d, double expectedValue) { var value = MathTrig.Acot(d); - var v = MathTrig.Cos(2d * MathTrig.Acos(2d)); - Assert.Equal(expectedValue, value); } diff --git a/MathTrigonometric/MathTrig.cs b/MathTrigonometric/MathTrig.cs index c73cce3..c189644 100644 --- a/MathTrigonometric/MathTrig.cs +++ b/MathTrigonometric/MathTrig.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; namespace MathTrigonometric; @@ -26,6 +27,22 @@ public static double Sin(double a) return Math.Sin(a); } + /// + /// Sine of the specific complex number. + /// + /// A complex number. + /// + /// The sine of the value. + /// This method returns NaN if equals + /// NaN, NegativeInfinity, or PositiveInfinity. + /// + public static Complex Sin(Complex z) + { + var sin = Math.Sin(z.Real); + var cos = Math.Cos(z.Real); + return new Complex(sin * Math.Cosh(z.Imaginary), cos * Math.Sinh(z.Imaginary)); + } + /// /// Cosine of the angle is ratio of the adjacent leg to hypotenuse. /// @@ -41,6 +58,22 @@ public static double Cos(double a) return Math.Cos(a); } + /// + /// Cosine of the specific complex number. + /// + /// A complex number. + /// + /// The cosine of the value. + /// This method returns NaN if equals + /// NaN, NegativeInfinity, or PositiveInfinity. + /// + public static Complex Cos(Complex z) + { + var sin = Math.Sin(z.Real); + var cos = Math.Cos(z.Real); + return new Complex(cos * Math.Cosh(z.Imaginary), -sin * Math.Sinh(z.Imaginary)); + } + /// /// Tangent of the angle is ratio of the opposite leg to adjacent one. /// @@ -60,6 +93,43 @@ public static double Tan(double a) return Math.Sin(a) / cos; } + /// + /// Tangent of the specific complex number. + /// + /// A complex number. + /// + /// The tangent of the value. + /// This method returns NaN if equals + /// NaN, NegativeInfinity, or PositiveInfinity. + /// + public static Complex Tan(Complex z) + { + // tan z = sin z / cos z, but to avoid unnecessary repeated trig computations, use + // tan z = (sin(2x) + i sinh(2y)) / (cos(2x) + cosh(2y)) + // (see Abramowitz & Stegun 4.3.57 or derive by hand), and compute trig functions here. + + // This approach does not work for |y| > ~355, because sinh(2y) and cosh(2y) overflow, + // even though their ratio does not. In that case, divide through by cosh to get: + // tan z = (sin(2x) / cosh(2y) + i \tanh(2y)) / (1 + cos(2x) / cosh(2y)) + // which correctly computes the (tiny) real part and the (normal-sized) imaginary part. + + double x2 = 2.0 * z.Real; + double y2 = 2.0 * z.Imaginary; + var sin = Math.Sin(x2); + var cos = Math.Cos(x2); + double cosh = Math.Cosh(y2); + if (Math.Abs(z.Imaginary) <= 4.0) + { + double D = cos + cosh; + return new Complex(sin / D, Math.Sinh(y2) / D); + } + else + { + double D = 1.0 + cos / cosh; + return new Complex(sin / cosh / D, Math.Tanh(y2) / D); + } + } + /// /// Cosecant of the angle is ratio of the hypotenuse to opposite leg. /// @@ -79,6 +149,24 @@ public static double Csc(double a) return 1.0 / sin; } + /// + /// Cosecant of the specific complex number. + /// + /// A complex number. + /// + /// The cosecant of the value. + /// This method returns NaN if equals + /// Zero, NaN, NegativeInfinity, or PositiveInfinity. + /// + public static Complex Csc(Complex z) + { + var sin = Sin(z); + if (sin == Complex.Zero) + return new Complex(double.NaN, double.NaN); + + return Complex.One / sin; + } + /// /// Secant of the angle is ratio of the hypotenuse to adjacent leg. /// @@ -98,6 +186,24 @@ public static double Sec(double a) return 1.0 / cos; } + /// + /// Secant of the specific complex number. + /// + /// A complex number. + /// + /// The secant of the value. + /// This method returns NaN if equals + /// NaN, NegativeInfinity, or PositiveInfinity. + /// + public static Complex Sec(Complex z) + { + var cos = Cos(z); + if (cos == Complex.Zero) + return new Complex(double.NaN, double.NaN); + + return Complex.One / cos; + } + /// /// Cotangent of the angle is ratio of the adjacent leg to opposite one. /// @@ -117,12 +223,30 @@ public static double Cot(double a) return Math.Cos(a) / sin; } + /// + /// Cotangent of the specific complex number. + /// + /// A complex number. + /// + /// The cotangent of the value. + /// This method returns NaN if equals + /// Zero, NaN, NegativeInfinity, or PositiveInfinity. + /// + public static Complex Cot(Complex z) + { + var sin = Math.Sin(z.Real); + var cos = Math.Cos(z.Real); + var coshI = Math.Cosh(z.Imaginary); + var sinhI = Math.Sinh(z.Imaginary); + return new Complex(cos * coshI, -sin * sinhI) / new Complex(sin * coshI, cos * sinhI); + } + #endregion #region Inverse Trigonometric Functions /// - /// Arc sine is inverse of the function. + /// Arc sine is inverse of the function. /// /// Value in range: [-1, 1]. /// @@ -137,7 +261,20 @@ public static double Asin(double d) } /// - /// Arc cosine is inverse of the function. + /// Arc sine of the specific complex number. + /// + /// A complex number. + /// + /// The arc sine of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Asin(Complex z) + { + return Complex.Asin(z); + } + + /// + /// Arc cosine is inverse of the function. /// /// Value in range: [-1, 1]. /// @@ -152,7 +289,20 @@ public static double Acos(double d) } /// - /// Arc tangent is inverse of the function. + /// Arc cosine of the specific complex number. + /// + /// A complex number. + /// + /// The arc cosine of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Acos(Complex z) + { + return Complex.Acos(z); + } + + /// + /// Arc tangent is inverse of the function. /// /// Any real number. /// @@ -168,7 +318,26 @@ public static double Atan(double d) } /// - /// Arc cosecant is inverse of the function. + /// Arc tangent of the specific complex number. + /// + /// A complex number. + /// + /// The arc tangent of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Atan(Complex z) + { + if (IsPositiveInfinity(z)) + return new Complex(Math.PI / 2, 0); + + if (IsNegativeInfinity(z)) + return new Complex(-Math.PI / 2, 0); + + return Complex.Atan(z); + } + + /// + /// Arc cosecant is inverse of the function. /// /// Value in range: (-∞, -1] ∪ [1, ∞). /// @@ -180,11 +349,24 @@ public static double Atan(double d) /// public static double Acsc(double d) { - return d == 0.0 ? double.NaN : Math.Asin(1.0 / d); + return Math.Asin(1.0 / d); } /// - /// Arc secant is inverse of the function. + /// Arc cosecant of the specific complex number. + /// + /// A complex number. + /// + /// The arc cosecant of the value. + /// This method returns NaN if equals Zero or NaN. + /// + public static Complex Acsc(Complex z) + { + return Complex.Asin(Complex.One / z); + } + + /// + /// Arc secant is inverse of the function. /// /// Value in range: (-∞, -1] ∪ [1, ∞). /// @@ -196,11 +378,24 @@ public static double Acsc(double d) /// public static double Asec(double d) { - return d == 0.0 ? double.NaN : Math.Acos(1.0 / d); + return Math.Acos(1.0 / d); + } + + /// + /// Arc secant of the specific complex number. + /// + /// A complex number. + /// + /// The arc secant of the value. + /// This method returns NaN if equals Zero or NaN. + /// + public static Complex Asec(Complex z) + { + return Complex.Acos(Complex.One / z); } /// - /// Arc cotangent is inverse of the > function. + /// Arc cotangent is inverse of the > function. /// /// Any real number. /// @@ -214,11 +409,35 @@ public static double Acot(double d) { //the Trigonometric Symmetry is applied: arccot(−x) = π − arccot(x) if (IsNegative(d)) - return Math.PI - Math.Atan(1 / -d); + return Math.PI - Math.Atan(1.0 / -d); return Math.Atan(1.0 / d); } + /// + /// Arc cotangent of the specific complex number. + /// + /// A complex number. + /// + /// The arc cotangent of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Acot(Complex z) + { + if (z == Complex.Zero) + return new Complex(Math.PI / 2, 0d); + + var oneOverZ = Complex.One / z; + if (IsInfinity(oneOverZ)) + return new Complex(Math.PI / 2, 0d); + + //the Trigonometric Symmetry is applied: arccot(−z) = π − arccot(z) + if (IsNegative(z.Real)) + return Math.PI - Complex.Atan(-oneOverZ); + + return Complex.Atan(oneOverZ); + } + #endregion #region Hyperbolic Trigonometric Functions @@ -241,6 +460,24 @@ public static double Sinh(double x) return Math.Sinh(x); } + /// + /// Hyperbolic sine of the specific complex number. + /// + /// A complex number. + /// + /// The hyperbolic sine of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Sinh(Complex z) + { + if (IsInfinity(z)) + return z; + + // Use sinh(z) = -i sin(iz) to compute via sin(z). + var sin = Sin(new Complex(-z.Imaginary, z.Real)); + return new Complex(sin.Imaginary, -sin.Real); + } + /// /// Hyperbolic cosine is defined as Cosh(x) = (e^x + e^−x)/2. /// @@ -259,6 +496,23 @@ public static double Cosh(double x) return Math.Cosh(x); } + /// + /// Hyperbolic cosine of the specific complex number. + /// + /// A complex number. + /// + /// The hyperbolic cosine of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Cosh(Complex z) + { + if (IsInfinity(z)) + return new Complex(double.PositiveInfinity, 0); + + // Use cosh(z) = cos(iz) to compute via cos(z). + return Cos(new Complex(-z.Imaginary, z.Real)); + } + /// /// Hyperbolic tangent is defined as Tanh(x) = (e^x − e^−x)/(e^x + e^−x). /// @@ -275,6 +529,21 @@ public static double Tanh(double x) return Math.Tanh(x); } + /// + /// Hyperbolic tangent of the specific complex number. + /// + /// A complex number. + /// + /// The hyperbolic tangent of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Tanh(Complex z) + { + // Use tanh(z) = -i tan(iz) to compute via tan(z). + var tan = Tan(new Complex(-z.Imaginary, z.Real)); + return new Complex(tan.Imaginary, -tan.Real); + } + /// /// Hyperbolic cosecant is defined as Csch(x) = 2/(e^x − e^−x). /// @@ -295,6 +564,23 @@ public static double Csch(double x) return 1.0 / sin; } + /// + /// Hyperbolic cosecant of the specific complex number. + /// + /// A complex number. + /// + /// The hyperbolic cosecant of the value. + /// This method returns NaN if equals Zero or NaN. + /// + public static Complex Csch(Complex z) + { + var sin = Sinh(z); + if (sin == Complex.Zero) + return new Complex(double.NaN, double.NaN); + + return Complex.One / sin; + } + /// /// Hyperbolic secant is defined as Sech(x) = 2/(e^x + e^−x). /// @@ -309,12 +595,23 @@ public static double Csch(double x) public static double Sech(double x) { var cos = Math.Cosh(x); - if (cos == 0.0) - return double.NaN; - return 1.0 / cos; } + /// + /// Hyperbolic secant of the specific complex number. + /// + /// A complex number. + /// + /// The hyperbolic secant of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Sech(Complex z) + { + var cos = Cosh(z); + return Complex.One / cos; + } + /// /// Hyperbolic cotangent is defined as Coth(x) = (e^x + e^−x)/(e^x − e^−x). /// @@ -334,12 +631,28 @@ public static double Coth(double x) return 1.0 / Math.Tanh(x); } + /// + /// Hyperbolic cotangent of the specific complex number. + /// + /// A complex number. + /// + /// The hyperbolic cotangent of the value. + /// This method returns NaN if equals Zero or NaN. + /// + public static Complex Coth(Complex z) + { + if (z == Complex.Zero) + return new Complex(double.NaN, double.NaN); + + return Complex.One / Tanh(z); + } + #endregion #region Inverse Hyperbolic Trigonometric Functions /// - /// Arc-hyperbolic sine is inverse of the function is defined as Arsinh(x) = ln[x + √(x^2 + 1)]. + /// Arc-hyperbolic sine is inverse of the function is defined as Arsinh(x) = ln[x + √(x^2 + 1)]. /// /// Any real number. /// @@ -353,8 +666,8 @@ public static double Coth(double x) /// public static double Asinh(double x) { - if (double.IsNegativeInfinity(x)) - return double.NegativeInfinity; + if (double.IsInfinity(x)) + return x; //the Trigonometric Symmetry is applied: arsinh(−x)=−arsinh(x) if (IsNegative(x)) @@ -364,7 +677,27 @@ public static double Asinh(double x) } /// - /// Arc-hyperbolic cosine is inverse of the function is defined as Arcosh(x) = ln[x + √(x^2 - 1)]. + /// Arc-hyperbolic sine of the specific complex number. + /// + /// A complex number. + /// + /// The arc-hyperbolic sine of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Asinh(Complex z) + { + if (IsInfinity(z)) + return z; + + //the Trigonometric Symmetry is applied: arsinh(−z)=−arsinh(z) + if (IsNegative(z.Real)) + return -Complex.Log(-z + Complex.Sqrt(z * z + Complex.One)); + + return Complex.Log(z + Complex.Sqrt(z * z + Complex.One)); + } + + /// + /// Arc-hyperbolic cosine is inverse of the function is defined as Arcosh(x) = ln[x + √(x^2 - 1)]. /// /// Value in range: [1, +∞). /// @@ -385,7 +718,23 @@ public static double Acosh(double x) } /// - /// Arc-hyperbolic tangent is inverse of the function + /// Arc-hyperbolic cosine of the specific complex number. + /// + /// A complex number. + /// + /// The arc-hyperbolic cosine of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Acosh(Complex z) + { + if (IsInfinity(z)) + return new Complex(double.PositiveInfinity, 0d); + + return Complex.Log(z + Complex.Sqrt(z * z - Complex.One)); + } + + /// + /// Arc-hyperbolic tangent is inverse of the function /// is defined as Artanh(x) = ln[(1 + x)/(1 − x)]/2. /// /// Value in range: (-1, 1). @@ -412,7 +761,32 @@ public static double Atanh(double x) } /// - /// Arc-hyperbolic cosecant is inverse of the function + /// Arc-hyperbolic tangent of the specific complex number. + /// + /// A complex number. + /// + /// The arc-hyperbolic tangent of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Atanh(Complex z) + { + if (z == Complex.One) + return new Complex(double.PositiveInfinity, 0d); + + if (z == -Complex.One) + return new Complex(double.NegativeInfinity, 0d); + + if (IsPositiveInfinity(z)) + return new Complex(0d, -Math.PI / 2); + + if (IsNegativeInfinity(z)) + return new Complex(0d, Math.PI / 2); + + return Complex.Log((1.0 + z) / (1.0 - z)) / 2.0; + } + + /// + /// Arc-hyperbolic cosecant is inverse of the function /// is defined as Arcsch(x) = ln[1/x + √(1/(x^2) + 1)]. /// /// Value in range: (−∞, 0)∪(0, +∞). @@ -436,7 +810,34 @@ public static double Acsch(double x) } /// - /// Arc-hyperbolic secant is inverse of the function + /// Arc-hyperbolic cosecant of the specific complex number. + /// + /// A complex number. + /// + /// The arc-hyperbolic cosecant of the value. + /// This method returns NaN if equals Zero or NaN. + /// + public static Complex Acsch(Complex z) + { + if (z == Complex.Zero) + return new Complex(double.NaN, double.NaN); + + if (IsInfinity(z)) + return Complex.Zero; + + var zz = z * z; + if (zz == Complex.Zero) + return new Complex(IsNegative(z.Real) ? double.NegativeInfinity : double.PositiveInfinity, 0d); + + //the Trigonometric Symmetry is applied: arcsch(−z)=−arcsch(z) + if (IsNegative(z.Real)) + return -Complex.Log(1.0 / -z + Complex.Sqrt(1.0 / zz + 1.0)); + + return Complex.Log(1.0 / z + Complex.Sqrt(1.0 / zz + 1.0)); + } + + /// + /// Arc-hyperbolic secant is inverse of the function /// is defined as Arsech(x) = ln([1 + √(1 − x^2)]/x). /// /// Value in range: (0, 1]. @@ -455,7 +856,30 @@ public static double Asech(double x) } /// - /// Arc-hyperbolic cotangent is inverse of the function + /// Arc-hyperbolic secant of the specific complex number. + /// + /// A complex number. + /// + /// The arc-hyperbolic secant of the value. + /// This method returns NaN if equals Zero or NaN. + /// + public static Complex Asech(Complex z) + { + if (z == Complex.Zero) + return new Complex(double.NaN, double.NaN); + + if (IsInfinity(z)) + return new Complex(0d, Math.PI / 2); + + var zz = z * z; + if (zz == Complex.Zero) + return new Complex(double.PositiveInfinity, IsNegative(z.Real) ? Math.PI : 0d); + + return Complex.Log(1.0 / z + Complex.Sqrt(1.0 / zz - 1.0)); + } + + /// + /// Arc-hyperbolic cotangent is inverse of the function /// is defined as Arcoth(x) = ln[(1 + x)/(x − 1)]/2. /// /// Value in range: (−∞, -1)∪(1, +∞). @@ -477,6 +901,28 @@ public static double Acoth(double x) return Math.Log((x + 1.0) / (x - 1.0)) / 2.0; } + /// + /// Arc-hyperbolic cotangent of the specific complex number. + /// + /// A complex number. + /// + /// The arc-hyperbolic cotangent of the value. + /// This method returns NaN if equals NaN. + /// + public static Complex Acoth(Complex z) + { + if (z == Complex.One) + return new Complex(double.PositiveInfinity, 0d); + + if (z == -Complex.One) + return new Complex(double.NegativeInfinity, 0d); + + if (IsInfinity(z)) + return Complex.Zero; + + return Complex.Log((z + 1.0) / (z - 1.0)) / 2.0; + } + #endregion /// @@ -503,4 +949,19 @@ private static bool IsNegative(double d) { return BitConverter.DoubleToInt64Bits(d) < 0; } + + private static bool IsNegativeInfinity(Complex value) + { + return (value.Imaginary == 0.0) && double.IsNegativeInfinity(value.Real); + } + + private static bool IsPositiveInfinity(Complex value) + { + return (value.Imaginary == 0.0) && double.IsPositiveInfinity(value.Real); + } + + private static bool IsInfinity(Complex value) + { + return (value.Imaginary == 0.0) && double.IsInfinity(value.Real); + } } \ No newline at end of file diff --git a/MathTrigonometric/MathTrigonometric.csproj b/MathTrigonometric/MathTrigonometric.csproj index e35db64..480466d 100644 --- a/MathTrigonometric/MathTrigonometric.csproj +++ b/MathTrigonometric/MathTrigonometric.csproj @@ -15,9 +15,9 @@ git README.md math; trigonometric; trigonometry; cot; sec; csc; acot; asec; acsc; coth; sech; csch; acoth; asech; acsch; - It targets .NET Standard 2.0 and higner version. + It targets .NET Standard 2.0 and higher version. Supports double and complex numbers. LICENSE - 1.0.7 + 1.1.0 diff --git a/README.md b/README.md index 87c6f47..b81edee 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ Alternatively, you can install the package using the NuGet Package Manager Conso Install-Package MathTrigonometric ## Functions Included + +In version [1.1.0](https://github.com/AntonovAnton/math.trigonometric/releases/tag/1.1.0), support for complex numbers has been introduced through overloaded methods for the trigonometric functions listed below. This allows the library to handle both real and complex inputs seamlessly. + ### Basic Trigonometric Functions 1. **Sin**