Browse Source

Merge pull request #540 from diluculo/trigKahan

Updated some (hyperbolic) trig functions
spatial
Christoph Ruegg 9 years ago
committed by GitHub
parent
commit
7087f4ae1d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 148
      src/Numerics/Trigonometry.cs
  2. 81
      src/UnitTests/TrigonometryTest.cs

148
src/Numerics/Trigonometry.cs

@ -192,11 +192,10 @@ namespace MathNet.Numerics
return new Complex(Tan(value.Real), 0.0);
}
var cosr = Cos(value.Real);
var sinhi = Sinh(value.Imaginary);
var denom = (cosr * cosr) + (sinhi * sinhi);
// tan(z) = - j*tanh(j*z)
return new Complex(Sin(value.Real) * cosr / denom, sinhi * Cosh(value.Imaginary) / denom);
Complex z = Tanh(new Complex(-value.Imaginary, value.Real));
return new Complex(z.Imaginary, -z.Real);
}
/// <summary>
@ -221,11 +220,10 @@ namespace MathNet.Numerics
return new Complex(Cot(value.Real), 0d);
}
var sinr = Sin(value.Real);
var sinhi = Sinh(value.Imaginary);
var denom = (sinr * sinr) + (sinhi * sinhi);
// cot(z) = - j*coth(-j*z)
return new Complex(sinr * Cos(value.Real) / denom, -sinhi * Cosh(value.Imaginary) / denom);
Complex z = Coth(new Complex(value.Imaginary, -value.Real));
return new Complex(z.Imaginary, -z.Real);
}
/// <summary>
@ -449,9 +447,20 @@ namespace MathNet.Numerics
return new Complex(Sinh(value.Real), 0.0);
}
// sinh(x + j y) = sinh(x)*cos(y) + j*cosh(x)*sin(y)
// if x > huge, sinh(x + jy) = sign(x)*exp(|x|)/2*cos(y) + j*exp(|x|)/2*sin(y)
if (Math.Abs(value.Real) >= 22.0) // Taken from the msun library in FreeBSD
{
double h = Math.Exp(Math.Abs(value.Real)) * 0.5;
return new Complex(
Math.Sign(value.Real)*h*Cos(value.Imaginary),
h*Sin(value.Imaginary));
}
return new Complex(
Sinh(value.Real) * Cos(value.Imaginary),
Cosh(value.Real) * Sin(value.Imaginary));
Cosh(value.Real) * Sin(value.Imaginary));
}
/// <summary>
@ -476,6 +485,17 @@ namespace MathNet.Numerics
return new Complex(Cosh(value.Real), 0.0);
}
// cosh(x + j*y) = cosh(x)*cos(y) + j*sinh(x)*sin(y)
// if x > huge, cosh(x + j*y) = exp(|x|)/2*cos(y) + j*sign(x)*exp(|x|)/2*sin(y)
if (Math.Abs(value.Real) >= 22.0) // Taken from the msun library in FreeBSD
{
double h = Math.Exp(Math.Abs(value.Real)) * 0.5;
return new Complex(
h * Cos(value.Imaginary),
Math.Sign(value.Real) * h * Sin(value.Imaginary));
}
return new Complex(
Cosh(value.Real) * Cos(value.Imaginary),
Sinh(value.Real) * Sin(value.Imaginary));
@ -515,17 +535,31 @@ namespace MathNet.Numerics
return new Complex(Tanh(value.Real), 0.0);
}
var cosi = Cos(value.Imaginary);
var sinhr = Sinh(value.Real);
if (double.IsInfinity(sinhr))
// tanh(x + j*y) = (cosh(x)*sinh(x)/cos^2(y) + j*tan(y))/(1 + sinh^2(x)/cos^2(y))
// if |x| > huge, tanh(z) = sign(x) + j*4*cos(y)*sin(y)*exp(-2*|x|)
// if exp(-|x|) = 0, tanh(z) = sign(x)
// if tan(y) = +/- oo or 1/cos^2(y) = 1 + tan^2(y) = oo, tanh(z) = cosh(x)/sinh(x)
//
// The algorithm is based on Kahan.
if (Math.Abs(value.Real) >= 22.0) // Taken from the msun library in FreeBSD
{
return new Complex(double.IsPositiveInfinity(sinhr) ? 1 : -1, 0.0);
double e = Math.Exp(-Math.Abs(value.Real));
return e == 0.0
? new Complex(Math.Sign(value.Real), 0.0)
: new Complex(Math.Sign(value.Real), 4.0 * Math.Cos(value.Imaginary) * Math.Sin(value.Imaginary) * e * e);
}
var denom = (cosi * cosi) + (sinhr * sinhr);
double tani = Tan(value.Imaginary);
double beta = 1 + tani * tani; // beta = 1/cos^2(y) = 1 + t^2
double sinhr = Sinh(value.Real);
double coshr = Cosh(value.Real);
if (double.IsInfinity(tani))
return new Complex(coshr / sinhr, 0.0);
return new Complex(Cosh(value.Real) * sinhr / denom, cosi * Sin(value.Imaginary) / denom);
double denom = 1.0 + beta * sinhr * sinhr;
return new Complex(beta * coshr * sinhr / denom, tani / denom);
}
/// <summary>
@ -562,17 +596,9 @@ namespace MathNet.Numerics
return new Complex(Coth(value.Real), 0.0);
}
var sini = Sin(value.Imaginary);
var sinhr = Sinh(value.Real);
// Coth(z) = 1/tanh(z)
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);
return Complex.One / Tanh(value);
}
/// <summary>
@ -597,14 +623,34 @@ namespace MathNet.Numerics
return new Complex(Sech(value.Real), 0.0);
}
var exp = value.Exp();
// sech(x + j*y) = (cosh(x)/cos(y) - j*sinh(x)*tan(y)/cos(y))/(1 + sinh^2(x)/cos^2(y))
// if |x| > huge, sech(z) = 4*cosh(x)*cos(y)*exp(-2*|x|) - j*4*sinh(x)*tan(y)*cos(y)*exp(-2*|x|)
// if exp(-|x|) = 0, sech(z) = 0
// if tan(y) = +/- oo or 1/cos^2(y) = 1 + tan^2(y) = oo, sech(z) = -j*sign(tan(y))/sinh(x)
//
// The algorithm is based on Kahan.
double tani = Tan(value.Imaginary);
double cosi = Cos(value.Imaginary);
double beta = 1.0 + tani * tani;
double sinhr = Math.Sinh(value.Real);
double coshr = Math.Cosh(value.Real);
if (Math.Abs(value.Real) >= 22.0) // Taken from the msun library in FreeBSD
{
double e = Math.Exp(-Math.Abs(value.Real));
return e == 0.0
? new Complex(0, 0)
: new Complex(4.0 * coshr * cosi * e * e, -4.0 * sinhr * tani * cosi * e * e);
}
if (exp.IsInfinity())
if (double.IsInfinity(tani))
{
return Complex.Zero;
return new Complex(0.0, -Math.Sign(tani) / sinhr);
}
return 2 * exp / (exp.Square() + 1);
double denom = 1.0 + beta * sinhr * sinhr;
return new Complex(coshr / cosi / denom, -sinhr * tani / cosi / denom);
}
/// <summary>
@ -629,14 +675,34 @@ namespace MathNet.Numerics
return new Complex(Csch(value.Real), 0.0);
}
var exp = value.Exp();
// csch(x + j*y) = (sinh(x)*cot(y)/sin(y) - j*cosh(x)/sin(y))/(1 + sinh^2(x)/sin^2(y))
// if |x| > huge, csch(z) = 4*sinh(x)*cot(y)*sin(y)*exp(-2*|x|) - j*4*cosh(x)*sin(y)*exp(-2*|x|)
// if exp(-|x|) = 0, csch(z) = 0
// if cot(y) = +/- oo or 1/sin^2(x) = 1 + cot^2(x) = oo, csch(z) = sign(cot(y))/sinh(x)
//
// The algorithm is based on Kahan.
double coti = Cot(value.Imaginary);
double sini = Sin(value.Imaginary);
double beta = 1 + coti * coti;
double sinhr = Sinh(value.Real);
double coshr = Cosh(value.Real);
if (Math.Abs(value.Real) >= 22.0) // Taken from the msun library in FreeBSD
{
double e = Math.Exp(-Math.Abs(value.Real));
return e == 0.0
? new Complex(0, 0)
: new Complex(4.0 * sinhr * coti * sini * e * e, -4.0 * coshr * sini * e * e);
}
if (exp.IsInfinity())
if (double.IsInfinity(coti))
{
return Complex.Zero;
return new Complex(Math.Sign(coti) / sinhr, 0.0);
}
return 2 * exp / (exp.Square() - 1);
double denom = 1.0 + beta * sinhr * sinhr;
return new Complex(sinhr * coti / sini / denom, -coshr / sini / denom);
}
@ -647,7 +713,13 @@ namespace MathNet.Numerics
/// <returns>The hyperbolic angle, i.e. the area of its hyperbolic sector.</returns>
public static double Asinh(double value)
{
return Math.Log(value + Math.Sqrt((value * value) + 1), Math.E);
// asinh(x) = Sign(x) * ln(|x| + sqrt(x*x + 1))
// if |x| > huge, asinh(x) ~= Sign(x) * ln(2|x|)
if (Math.Abs(value) >= 268435456.0) // 2^28, taken from freeBSD
return Math.Sign(value) * (Math.Log(Math.Abs(value)) + Math.Log(2.0));
return Math.Sign(value) * Math.Log(Math.Abs(value) + Math.Sqrt((value * value) + 1));
}
/// <summary>
@ -667,6 +739,12 @@ namespace MathNet.Numerics
/// <returns>The hyperbolic angle, i.e. the area of its hyperbolic sector.</returns>
public static double Acosh(double value)
{
// acosh(x) = ln(x + sqrt(x*x - 1))
// if |x| >= 2^28, acosh(x) ~ ln(x) + ln(2)
if (Math.Abs(value) >= 268435456.0) // 2^28, taken from freeBSD
return Math.Log(value) + Math.Log(2.0);
return Math.Log(value + (Math.Sqrt(value - 1) * Math.Sqrt(value + 1)), Math.E);
}

81
src/UnitTests/TrigonometryTest.cs

@ -58,6 +58,12 @@ namespace MathNet.Numerics.UnitTests
[TestCase(-1.19209289550780998537e-7, 0.0, 0.99999999999999289, 0.0)]
[TestCase(8.388608e6, 1.19209289550780998537e-7, -0.90175467375876572, -5.1528001100635277e-8)]
[TestCase(-1.19209289550780998537e-7, -8.388608e6, double.PositiveInfinity, double.NegativeInfinity)]
[TestCase(512.0, 32.0, -39356457675156.6, -3139507838262.74)]
[TestCase(-512.0, -32.0, -39356457675156.6, -3139507838262.74)]
[TestCase(32.0, -512.0, +9.52855589474963e+221, +6.29843301304523e+221)]
[TestCase(-32.0, -512.0, +9.52855589474963e+221, -6.29843301304523e+221)]
[TestCase(355.0, 355.0, -7.4732769989672537746e153, +2.25277102712558920722e149)]
[TestCase(355.58, 355.58, -1.11645148443766450218e154, +7.31511888973169437082e153)]
public void CanComputeComplexCosine(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Cos();
@ -79,6 +85,12 @@ namespace MathNet.Numerics.UnitTests
[TestCase(-1.19209289550780998537e-7, 0.0, -1.19209289550780998537e-7, 0.0)]
[TestCase(8.388608e6, 1.19209289550780998537e-7, 0.43224820225680083, -1.0749753400787824e-7)]
[TestCase(-1.19209289550780998537e-7, -8.388608e6, double.NegativeInfinity, double.NegativeInfinity)]
[TestCase(512.0, 32.0, +3139507838262.74, -39356457675156.6)]
[TestCase(-512.0, -32.0, -3139507838262.74, +39356457675156.6)]
[TestCase(32.0, -512.0, +6.29843301304523e+221, -9.52855589474963e+221)]
[TestCase(-32.0, -512.0, -6.29843301304523e+221, -9.52855589474963e+221)]
[TestCase(355.0, 355.0, -2.25277102712558920722e149, -7.4732769989672537746e153)]
[TestCase(355.58, 355.58, -+7.31511888973169437082e153, -1.11645148443766450218e154)]
public void CanComputeComplexSine(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Sin();
@ -100,6 +112,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(-1.19209289550780998537e-7, 0.0, -1.1920928955078157e-7, 0.0)]
[TestCase(8.388608e6, 1.19209289550780998537e-7, -0.47934123862653449, 1.4659977233982276e-7)]
[TestCase(-8.388608e6, -1.19209289550780998537e-7, 0.47934123862653449, -1.4659977233982276e-7)]
[TestCase(512.0, 32.0, -5.08515122860094E-29, 1)]
[TestCase(-512.0, -32.0, +5.08515122860094E-29, -1)]
[TestCase(32.0, 512.0, +3.52598650243739e-445, 1)]
[TestCase(32.0, -512.0, +3.52598650243739e-445, -1)]
[TestCase(355.0, 355.0, +5.39739014654622322424e-313, +1.0)]
[TestCase(355.58, 355.58, +2.57308259096360322163e-309, +1.0)]
[TestCase(196.0, 16.0, +1.62991625102252204721e-14, +1.00000000000001938715)]
public void CanComputeComplexTangent(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Tan();
@ -319,6 +338,7 @@ namespace MathNet.Numerics.UnitTests
/// <param name="expected">Expected value.</param>
[TestCase(1.0, 0.0)]
[TestCase(8388608, 16.635532333438682)]
[TestCase(1.7976931348623157E+308, 710.47586007394394203711)]
public void CanComputeInverseHyperbolicCosine(double value, double expected)
{
var actual = Trig.Acosh(value);
@ -364,6 +384,8 @@ namespace MathNet.Numerics.UnitTests
[TestCase(-8388608, -16.63553233343869)]
[TestCase(1.19209289550780998537e-7, 1.1920928955078072e-7)]
[TestCase(-1.19209289550780998537e-7, -1.1920928955078072e-7)]
[TestCase(1.7976931348623157E+308, 710.47586007394394203711)]
[TestCase(-1.7976931348623157E+308, -710.47586007394394203711)]
public void CanComputeInverseHyperbolicSine(double value, double expected)
{
var actual = Trig.Asinh(value);
@ -549,6 +571,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(-1.19209289550780998537e-7, 0.0, -8388607.999999978, 0.0)]
[TestCase(8.388608e6, 1.19209289550780998537e-7, -2.0861964701080704, -6.3803383253713457e-7)]
[TestCase(-8.388608e6, -1.19209289550780998537e-7, 2.0861964701080704, 6.3803383253713457e-7)]
[TestCase(512.0, 32.0, -5.08515122860094E-29, -1.0)]
[TestCase(-512.0, -32.0, 5.08515122860094E-29, +1.0)]
[TestCase(32.0, 512.0, +3.52598650243739e-445, -1.0)]
[TestCase(32.0, -512.0, +3.52598650243739e-445, +1.0)]
[TestCase(355.0, 355.0, +5.39739014654622322424e-313, -1.0)]
[TestCase(355.58, 355.58, +2.57308259096360322163e-309, -1.0)]
[TestCase(196.0, 16.0, +1.62991625102252204721e-14, -1.00000000000001938715)]
public void CanComputeComplexCotangent(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Cot();
@ -570,6 +599,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(-1.19209289550780998537e-7, 0.0, 1.0000000000000071, 0.0)]
[TestCase(8.388608e6, 1.19209289550780998537e-7, -1.1089490624226177, 6.3367488045143761e-8)]
[TestCase(-8.388608e6, -1.19209289550780998537e-7, -1.1089490624226177, 6.3367488045143761e-8)]
[TestCase(512.0, 32.0, -2.52481261731330570134e-14, +2.01407074478744036413e-15)]
[TestCase(-512.0, -32.0, -2.52481261731330570134e-14, +2.01407074478744036413e-15)]
[TestCase(32.0, 512.0, +7.30361056703505e-223, +4.82773070945482e-223)]
[TestCase(32.0, -512.0, +7.30361056703505e-223, -4.82773070945482e-223)]
[TestCase(355.0, 355.0, -1.33810107564527561878e-154, -4.03361916732891580715e-159)]
[TestCase(355.58, 355.58, -6.26665948010988663559e-155, -4.10598756663013051681e-155)]
[TestCase(196.0, 16.0, +7.70790453157574313253e-8, +2.11460357915116320189e-7)]
public void CanComputeComplexSecant(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Sec();
@ -591,6 +627,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(-1.19209289550780998537e-7, 0.0, -8388608.0000000376, 0.0)]
[TestCase(8.388608e6, 1.19209289550780998537e-7, 2.3134856195557596, 5.7534999050657057e-7)]
[TestCase(-8.388608e6, -1.19209289550780998537e-7, -2.3134856195557596, -5.7534999050657057e-7)]
[TestCase(512.0, 32.0, 2.01407074478744e-15, 2.52481261731331e-14)]
[TestCase(-512.0, -32.0, -2.01407074478744e-15, -2.52481261731331e-14)]
[TestCase(32.0, 512.0, +4.82773070945482e-223, -7.30361056703505e-223)]
[TestCase(32.0, -512.0, +4.82773070945482e-223, +7.30361056703505e-223)]
[TestCase(355.0, 355.0, -4.03361916732891580715e-159, +1.33810107564527561878e-154)]
[TestCase(355.58, 355.58, -4.10598756663013051681e-155, +6.26665948010988663559e-155)]
[TestCase(196.0, 16.0, +2.11460357915116320189e-7, -7.70790453157574313253e-8)]
public void CanComputeComplexCosecant(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Csc();
@ -616,6 +659,11 @@ namespace MathNet.Numerics.UnitTests
[TestCase(0.5, -0.5, 0.45730415318424922, -0.54061268571315335)]
[TestCase(-0.5, 0.5, -0.45730415318424922, 0.54061268571315335)]
[TestCase(-0.5, -0.5, -0.45730415318424922, -0.54061268571315335)]
[TestCase(512.0, 32.0, 9.52855589474962752845e221, 6.29843301304522728211e221)]
[TestCase(-512.0, -32.0, -9.52855589474962752845e221, -6.29843301304522728211e221)]
[TestCase(-32.0, 512.0, +3.93564576751566e13, +3.13950783826274e12)]
[TestCase(32.0, -512.0, -3.93564576751566e13, -3.13950783826274e12)]
[TestCase(709.0, 709.0, +2.22042071181169647963e307, -3.45764185010438140812e307)]
public void CanComputeComplexHyperbolicSine(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Sinh();
@ -641,6 +689,11 @@ namespace MathNet.Numerics.UnitTests
[TestCase(0.5, -0.5, 0.9895848833999199, -0.24982639750046154)]
[TestCase(-0.5, 0.5, 0.9895848833999199, -0.24982639750046154)]
[TestCase(-0.5, -0.5, 0.9895848833999199, 0.24982639750046154)]
[TestCase(512.0, 32.0, 9.52855589474962752845e221, 6.29843301304522728211e221)]
[TestCase(-512.0, -32.0, 9.52855589474962752845e221, 6.29843301304522728211e221)]
[TestCase(-32.0, 512.0, -3.93564576751566e13, -3.13950783826274e12)]
[TestCase(32.0, -512.0, -3.93564576751566e13, -3.13950783826274e12)]
[TestCase(709.0, 709.0, +2.22042071181169647963e307, -3.45764185010438140812e307)]
public void CanComputeComplexHyperbolicCosine(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Cosh();
@ -666,6 +719,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(0.5, -0.5, 0.56408314126749848, -0.40389645531602575)]
[TestCase(-0.5, 0.5, -0.56408314126749848, 0.40389645531602575)]
[TestCase(-0.5, -0.5, -0.56408314126749848, -0.40389645531602575)]
[TestCase(512.0, 32.0, 1.0, 0.0)]
[TestCase(-512.0, -32.0, -1.0, 0.0)]
[TestCase(-32.0, 512.0, -1.0, -5.08515122860093626173e-29)]
[TestCase(32.0, -512.0, +1.0, +5.08515122860093626173e-29)]
[TestCase(355.0, 355.0, +1.0, +5.39739014654622322424e-313)]
[TestCase(355.58, 355.58, +1.0, +2.57308259096360322163e-309)]
[TestCase(196.0, 16.0, +1.0, +6.29623407730470174659e-171)]
public void CanComputeComplexHyperbolicTangent(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Tanh();
@ -691,6 +751,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(0.5, -0.5, 1.1719451445243514, 0.8391395790248311)]
[TestCase(-0.5, 0.5, -1.1719451445243514, -0.8391395790248311)]
[TestCase(-0.5, -0.5, -1.1719451445243514, 0.8391395790248311)]
[TestCase(512.0, 32.0, 1.0, 0.0)]
[TestCase(-512.0, -32.0, -1.0, 0.0)]
[TestCase(-32.0, 512.0, -1.0, 5.08515122860093626173e-29)]
[TestCase(32.0, -512.0, +1.0, -5.08515122860093626173e-29)]
[TestCase(355.0, 355.0, +1.0, -5.39739014654622322424e-313)]
[TestCase(355.58, 355.58, +1.0, -2.57308259096360322163e-309)]
[TestCase(196.0, 16.0, +1.0, -6.29623407730470174659e-171)]
public void CanComputeComplexHyperbolicCotangent(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Coth();
@ -716,6 +783,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(0.5, -0.5, 0.94997886761549463, 0.23982763093808804)]
[TestCase(-0.5, 0.5, 0.94997886761549463, 0.23982763093808804)]
[TestCase(-0.5, -0.5, 0.94997886761549463, -0.23982763093808804)]
[TestCase(512.0, 32.0, 7.30361056703505051822e-223, -4.82773070945482080706e-223)]
[TestCase(-512.0, -32.0, 7.30361056703505051822e-223, -4.82773070945482080706e-223)]
[TestCase(-32.0, 512.0, -2.52481261731330570134e-14, +2.01407074478744036413e-15)]
[TestCase(-32.0, -512.0, -2.52481261731330570134e-14, -2.01407074478744036413e-15)]
[TestCase(355.0, 355.0, -1.33810107564527561878e-154, +4.03361916732891580715e-159)]
[TestCase(355.58, 355.58, -6.26665948010988663559e-155, +4.10598756663013051681e-155)]
[TestCase(196.0, 16.0, -1.447180343166980306269e-85, +4.350690711792111509525e-86)]
public void CanComputeComplexHyperbolicSecant(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Sech();
@ -741,6 +815,13 @@ namespace MathNet.Numerics.UnitTests
[TestCase(0.5, -0.5, 0.91207426403881078, 1.0782296946540223)]
[TestCase(-0.5, 0.5, -0.91207426403881078, -1.0782296946540223)]
[TestCase(-0.5, -0.5, -0.91207426403881078, 1.0782296946540223)]
[TestCase(512.0, 32.0, 7.30361056703505051822e-223, -4.82773070945482080706e-223)]
[TestCase(-512.0, -32.0, -7.30361056703505051822e-223, +4.82773070945482080706e-223)]
[TestCase(-32.0, 512.0, +2.52481261731330570134e-14, -2.01407074478744036413e-15)]
[TestCase(32.0, -512.0, -2.52481261731330570134e-14, +2.01407074478744036413e-15)]
[TestCase(355.0, 355.0, -1.33810107564527561878e-154, +4.03361916732891580715e-159)]
[TestCase(355.58, 355.58, -6.26665948010988663559e-155, +4.10598756663013051681e-155)]
[TestCase(196.0, 16.0, -1.447180343166980306269e-85, +4.350690711792111509525e-86)]
public void CanComputeComplexHyperbolicCosecant(double real, double imag, double expectedReal, double expectedImag)
{
var actual = new Complex(real, imag).Csch();

Loading…
Cancel
Save