diff --git a/src/Numerics.Tests/SpecialFunctionsTests/BesselTests.cs b/src/Numerics.Tests/SpecialFunctionsTests/BesselTests.cs index 8550759d..60ed1416 100644 --- a/src/Numerics.Tests/SpecialFunctionsTests/BesselTests.cs +++ b/src/Numerics.Tests/SpecialFunctionsTests/BesselTests.cs @@ -241,5 +241,36 @@ namespace MathNet.Numerics.UnitTests.SpecialFunctionsTests } #endregion + + #region Ratio of Bessel I : I(n + 1, z) / I(n, z) + + [TestCase(0, 1, 1, 0.57495795977223997079, 0.35054769385125934266, 14)] + [TestCase(0, 10, 10, 0.97503660846868673171, 0.025655591609138262390, 14)] + [TestCase(0, 100, 100, 0.99750003174335729017, 0.0025062812447888833561, 12)] + [TestCase(0, 1E6, 1E6, 0.99999975000000000003, 2.5000006250003125000E-7, 8)] // cf. BesselI(0, 1e6 + 1e6 j) = 7.4E434290 - 6.9E434290 j and BesselI(1, 1e6 + 1e6 j) = 7.4E434290 - 6.9E434290 j + public void BesselIRatioExact(int n, double zr, double zi, double cyr, double cyi, int decimalPlaces) + { + var z = new Complex(zr, zi); + var actual = SpecialFunctions.BesselI(n + 1, z, true) / SpecialFunctions.BesselI(n, z, true); + AssertHelpers.AlmostEqualRelative(new Complex(cyr, cyi), actual, decimalPlaces); + } + + #endregion + + #region Ratio of Bessel K : K(n + 1, z) / K(n, z) + + [TestCase(0, 1E-6, 1E-6, 38803.844378426554737, -34562.243460439510287, 14)] + [TestCase(0, 1, 1, 1.2397012468882428039, -0.20950920530836317445, 14)] + [TestCase(0, 10, 10, 1.0249731393042359657, -0.024405853995209668702, 14)] + [TestCase(0, 100, 100, 1.0024999692332050665, -0.0024937812450508461147, 12)] + [TestCase(0, 1E6, 1E6, 1.0000002500000000000, -2.4999993750003125000E-7, 9)] + public void BesselKRatioExact(int n, double zr, double zi, double cyr, double cyi, int decimalPlaces) + { + var z = new Complex(zr, zi); + var actual = SpecialFunctions.BesselK(n + 1, z, true) / SpecialFunctions.BesselK(n, z, true); + AssertHelpers.AlmostEqualRelative(new Complex(cyr, cyi), actual, decimalPlaces); + } + + #endregion } } diff --git a/src/Numerics/SpecialFunctions/Airy.cs b/src/Numerics/SpecialFunctions/Airy.cs index 6bf2c7d9..26ef5c13 100644 --- a/src/Numerics/SpecialFunctions/Airy.cs +++ b/src/Numerics/SpecialFunctions/Airy.cs @@ -12,87 +12,127 @@ namespace MathNet.Numerics public static partial class SpecialFunctions { /// - /// Airy function Ai + /// Airy function Ai(z). + ///

+ /// If expScaled is true, returns Exp(zta) * Ai(z), where zta = (2/3) * z * Sqrt(z). ///

/// The value to compute the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static Complex AiryAi(Complex z) + public static Complex AiryAi(Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cairy(z); + return (expScaled) ? amos.ScaledCairy(z) : amos.Cairy(z); } /// - /// Airy function Ai + /// Airy function Ai(z). + ///

+ /// If expScaled is true, returns Exp(zta) * Ai(z), where zta = (2/3) * z * Sqrt(z). ///

- /// The value to compute the Airy function of. + /// The value to compute the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static double AiryAi(double x) + public static double AiryAi(double z, bool expScaled = false) { - return AiryAi(new Complex(x, 0)).Real; + if (expScaled) + { + var amos = new AmosWrapper(); + return amos.ScaledCairy(z); + } + else + { + return AiryAi(new Complex(z, 0), expScaled).Real; + } } /// - /// Derivative of the Airy function Ai + /// Derivative of the Airy function Ai. + ///

+ /// If expScaled is true, returns Exp(zta) * d/dz Ai(z), where zta = (2/3) * z * Sqrt(z). ///

/// The value to compute the derivative of the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static Complex AiryAiPrime(Complex z) + public static Complex AiryAiPrime(Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.CairyPrime(z); + return (expScaled) ? amos.ScaledCairyPrime(z) : amos.CairyPrime(z); } /// - /// Derivative of the Airy function Ai + /// Derivative of the Airy function Ai. + ///

+ /// If expScaled is true, returns Exp(zta) * d/dz Ai(z), where zta = (2/3) * z * Sqrt(z). ///

- /// The value to compute the derivative of the Airy function of. + /// The value to compute the derivative of the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static double AiryAiPrime(double x) + public static double AiryAiPrime(double z, bool expScaled = false) { - return AiryAiPrime(new Complex(x, 0)).Real; + if (expScaled) + { + var amos = new AmosWrapper(); + return amos.ScaledCairyPrime(z); + } + else + { + return AiryAiPrime(new Complex(z, 0), expScaled).Real; + } } /// - /// Airy function Bi(z) + /// Airy function Bi(z). + ///

+ /// If expScaled is true, returns Exp(-axzta) * Bi(z) where zta = (2 / 3) * z * Sqrt(z) and axzta = Abs(zta.Real). ///

/// The value to compute the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static Complex AiryBi(Complex z) + public static Complex AiryBi(Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cbiry(z); + return (expScaled) ? amos.ScaledCbiry(z) : amos.Cbiry(z); } /// - /// Airy function Bi(x) + /// Airy function Bi(x). + ///

+ /// If expScaled is true, returns Exp(-axzta) * Bi(z) where zta = (2 / 3) * z * Sqrt(z) and axzta = Abs(zta.Real). ///

- /// The value to compute the Airy function of. + /// The value to compute the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static double AiryBi(double x) + public static double AiryBi(double z, bool expScaled = false) { - return AiryBi(new Complex(x, 0)).Real; + return AiryBi(new Complex(z, 0), expScaled).Real; } /// - /// Derivative of the Airy function Bi(z) + /// Derivative of the Airy function Bi(z). + ///

+ /// If expScaled is true, returns Exp(-axzta) * d/dz Bi(z) where zta = (2 / 3) * z * Sqrt(z) and axzta = Abs(zta.Real). ///

/// The value to compute the derivative of the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static Complex AiryBiPrime(Complex z) + public static Complex AiryBiPrime(Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.CbiryPrime(z); + return (expScaled) ? amos.ScaledCbiryPrime(z) : amos.CbiryPrime(z); } /// - /// Derivative of the Airy function Bi(z) + /// Derivative of the Airy function Bi(z). + ///

+ /// If expScaled is true, returns Exp(-axzta) * d/dz Bi(z) where zta = (2 / 3) * z * Sqrt(z) and axzta = Abs(zta.Real). ///

- /// The value to compute the derivative of the Airy function of. + /// The value to compute the derivative of the Airy function of. + /// If true, returns exponentially-scaled Airy function /// - public static double AiryBiPrime(double x) + public static double AiryBiPrime(double z, bool expScaled = false) { - return AiryBiPrime(new Complex(x, 0)).Real; + return AiryBiPrime(new Complex(z, 0), expScaled).Real; } } } diff --git a/src/Numerics/SpecialFunctions/Amos/AmosWrapper.cs b/src/Numerics/SpecialFunctions/Amos/AmosWrapper.cs index 7c143e67..68d9ee1a 100644 --- a/src/Numerics/SpecialFunctions/Amos/AmosWrapper.cs +++ b/src/Numerics/SpecialFunctions/Amos/AmosWrapper.cs @@ -14,6 +14,7 @@ namespace MathNet.Numerics { #region AiryAi + // Returns Ai(z) public Complex Cairy(Complex z) { int id = 0; @@ -29,6 +30,44 @@ namespace MathNet.Numerics return new Complex(air, aii); } + // Returns Exp(zta) * Ai(z) where zta = (2/3) * z * Sqrt(z) + public Complex ScaledCairy(Complex z) + { + int id = 0; + int kode = 2; + int nz = 0; + int ierr = 0; + + double air = double.NaN; + double aii = double.NaN; + + var amos = new AmosHelper(); + amos.zairy(z.Real, z.Imaginary, id, kode, ref air, ref aii, ref nz, ref ierr); + return new Complex(air, aii); + } + + // Returns Exp(zta) * Ai(z) where zta = (2/3) * z * Sqrt(z) + public double ScaledCairy(double z) + { + if (z < 0) + { + return double.NaN; + } + + int id = 0; + int kode = 2; + int nz = 0; + int ierr = 0; + + double air = double.NaN; + double aii = double.NaN; + + var amos = new AmosHelper(); + amos.zairy(z, 0.0, id, kode, ref air, ref aii, ref nz, ref ierr); + return air; + } + + // Returns d/dz Ai(z) public Complex CairyPrime(Complex z) { int id = 1; @@ -44,10 +83,48 @@ namespace MathNet.Numerics return new Complex(air, aii); } + // Returns Exp(zta) * d/dz Ai(z) where zta = (2/3) * z * Sqrt(z) + public Complex ScaledCairyPrime(Complex z) + { + int id = 1; + int kode = 2; + int nz = 0; + int ierr = 0; + + double air = double.NaN; + double aii = double.NaN; + + var amos = new AmosHelper(); + amos.zairy(z.Real, z.Imaginary, id, kode, ref air, ref aii, ref nz, ref ierr); + return new Complex(air, aii); + } + + // Returns Exp(zta) * d/dz Ai(z) where zta = (2/3) * z * Sqrt(z) + public double ScaledCairyPrime(double z) + { + if (z < 0) + { + return double.NaN; + } + + int id = 1; + int kode = 2; + int nz = 0; + int ierr = 0; + + double air = double.NaN; + double aii = double.NaN; + + var amos = new AmosHelper(); + amos.zairy(z, 0.0, id, kode, ref air, ref aii, ref nz, ref ierr); + return air; + } + #endregion #region AiryBi + // Returns Bi(z) public Complex Cbiry(Complex z) { int id = 0; @@ -63,6 +140,23 @@ namespace MathNet.Numerics return new Complex(bir, bii); } + // Returns Exp(-axzta) * Bi(z) where zta = (2 / 3) * z * Sqrt(z) and axzta = Abs(zta.Real) + public Complex ScaledCbiry(Complex z) + { + int id = 0; + int kode = 2; + int nz = 0; + int ierr = 0; + + double bir = double.NaN; + double bii = double.NaN; + + var amos = new AmosHelper(); + amos.zbiry(z.Real, z.Imaginary, id, kode, ref bir, ref bii, ref nz, ref ierr); + return new Complex(bir, bii); + } + + // Returns d/dz Bi(z) public Complex CbiryPrime(Complex z) { int id = 1; @@ -78,10 +172,27 @@ namespace MathNet.Numerics return new Complex(bipr, bipi); } + // Returns Exp(-axzta) * d/dz Bi(z) where zta = (2 / 3) * z * Sqrt(z) and axzta = Abs(zta.Real) + public Complex ScaledCbiryPrime(Complex z) + { + int id = 1; + int kode = 2; + int nz = 0; + int ierr = 0; + + double bipr = double.NaN; + double bipi = double.NaN; + + var amos = new AmosHelper(); + amos.zbiry(z.Real, z.Imaginary, id, kode, ref bipr, ref bipi, ref nz, ref ierr); + return new Complex(bipr, bipi); + } + #endregion #region BesselJ + // Return J(v, z) public Complex Cbesj(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) @@ -115,7 +226,7 @@ namespace MathNet.Numerics if (ierr == 2) { //overflow - cyj = CbesjScaled(v, z); + cyj = ScaledCbesj(v, z); cyj = new Complex(cyj.Real * double.PositiveInfinity, cyj.Imaginary * double.PositiveInfinity); } @@ -145,7 +256,19 @@ namespace MathNet.Numerics return cyj; } - private Complex CbesjScaled(double v, Complex z) + // Return J(v, z) + public double Cbesj(double v, double z) + { + if (z < 0 && v != (int)v) + { + return double.NaN; + } + + return Cbesj(v, new Complex(z, 0)).Real; + } + + // Return Exp(-Abs(y)) * J(v, z) where y = z.Imaginary + public Complex ScaledCbesj(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) { @@ -201,10 +324,22 @@ namespace MathNet.Numerics return cyj; } + // Return Exp(-Abs(y)) * J(v, z) where y = z.Imaginary + public double ScaledCbesj(double v, double z) + { + if (z < 0 && v != (int)v) + { + return double.NaN; + } + + return ScaledCbesj(v, new Complex(z, 0)).Real; + } + #endregion #region BesselY + // Return Y(v, z) public Complex Cbesy(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) @@ -279,7 +414,8 @@ namespace MathNet.Numerics return cyy; } - public double CbesyReal(double v, double x) + // Return Y(v, z) + public double Cbesy(double v, double x) { if (x < 0.0) { @@ -290,10 +426,87 @@ namespace MathNet.Numerics return Cbesy(v, z).Real; } + // Return Exp(-Abs(y)) * Y(v, z) where y = z.Imaginary + public Complex ScaledCbesy(double v, Complex z) + { + if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) + { + return new Complex(double.NaN, double.NaN); + } + + int sign = 1; + if (v < 0) + { + v = -v; + sign = -1; + } + + int n = 1; + int kode = 2; + int nz = 0; + int ierr = 0; + + double[] cyyr = new double[n]; + double[] cyyi = new double[n]; + double[] cwrkr = new double[n]; + double[] cwrki = new double[n]; + for (int i = 0; i < n; i++) + { + cyyr[i] = double.NaN; + cyyi[i] = double.NaN; + cwrkr[i] = double.NaN; + cwrki[i] = double.NaN; + } + + var amos = new AmosHelper(); + amos.zbesy(z.Real, z.Imaginary, v, kode, n, cyyr, cyyi, ref nz, cwrkr, cwrki, ref ierr); + Complex cyy = new Complex(cyyr[0], cyyi[0]); + + if (ierr == 2) + { + if (z.Real >= 0 && z.Imaginary == 0) + { + //overflow + cyy = new Complex(double.PositiveInfinity, 0); + } + } + + if (sign == -1) + { + if (!ReflectJY(ref cyy, v)) + { + double[] cyjr = new double[n]; + double[] cyji = new double[n]; + for (int i = 0; i < n; i++) + { + cyjr[i] = double.NaN; + cyji[i] = double.NaN; + } + + amos.zbesj(z.Real, z.Imaginary, v, kode, n, cyjr, cyji, ref nz, ref ierr); + Complex cyj = new Complex(cyjr[0], cyji[0]); + cyy = RotateJY(cyy, cyj, -v); + } + } + return cyy; + } + + // Return Exp(-Abs(y)) * Y(v, z) where y = z.Imaginary + public double ScaledCbesy(double v, double x) + { + if (x < 0) + { + return double.NaN; + } + + return ScaledCbesy(v, new Complex(x, 0)).Real; + } + #endregion #region BesselI + // Returns I(v, z) public Complex Cbesi(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) @@ -337,7 +550,7 @@ namespace MathNet.Numerics } else { - cyi = CbesiScaled(v * sign, z); + cyi = ScaledCbesi(v * sign, z); cyi = new Complex(cyi.Real * double.PositiveInfinity, cyi.Imaginary * double.PositiveInfinity); } } @@ -358,7 +571,8 @@ namespace MathNet.Numerics return cyi; } - private Complex CbesiScaled(double v, Complex z) + // Return Exp(-Abs(x)) * I(v, z) where x = z.Real + public Complex ScaledCbesi(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) { @@ -412,10 +626,22 @@ namespace MathNet.Numerics return cyi; } + // Return Exp(-Abs(x)) * I(v, z) where x = z.Real + public double ScaledCbesi(double v, double x) + { + if (v != Math.Floor(v) && x < 0) + { + return double.NaN; + } + + return ScaledCbesi(v, new Complex(x, 0)).Real; + } + #endregion #region BesselK + // Returns K(v, z) public Complex Cbesk(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) @@ -463,8 +689,9 @@ namespace MathNet.Numerics return cyk; } - - public double CbeskReal(double v, double z) + + // Returns K(v, z) + public double Cbesk(double v, double z) { if (z < 0) { @@ -489,10 +716,73 @@ namespace MathNet.Numerics } } + // returns Exp(z) * K(v, z) + public Complex ScaledCbesk(double v, Complex z) + { + if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) + { + return new Complex(double.NaN, double.NaN); + } + + if (v < 0) + { + //K_v == K_{-v} even for non-integer v + v = -v; + } + + int n = 1; + int kode = 2; + int nz = 0; + int ierr = 0; + + double[] cykr = new double[n]; + double[] cyki = new double[n]; + for (int i = 0; i < n; i++) + { + cykr[i] = double.NaN; + cyki[i] = double.NaN; + } + + var amos = new AmosHelper(); + + amos.zbesk(z.Real, z.Imaginary, v, kode, n, cykr, cyki, ref nz, ref ierr); + Complex cyk = new Complex(cykr[0], cyki[0]); + + if (ierr == 2) + { + if (z.Real >= 0 && z.Imaginary == 0) + { + //overflow + cyk = new Complex(double.PositiveInfinity, 0); + } + } + + return cyk; + } + + // returns Exp(z) * K(v, z) + public double ScaledCbesk(double v, double z) + { + if (z < 0) + { + return double.NaN; + } + else if (z == 0) + { + return double.PositiveInfinity; + } + else + { + Complex w = new Complex(z, 0); + return ScaledCbesk(v, w).Real; + } + } + #endregion #region HankelH1 + // Returns H1(v, z) public Complex Cbesh1(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) @@ -533,10 +823,52 @@ namespace MathNet.Numerics return cyh; } + // Returns Exp(-z * j) * H1(n, z) where j = Sqrt(-1) + public Complex ScaledCbesh1(double v, Complex z) + { + if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) + { + return new Complex(double.NaN, double.NaN); ; + } + + int n = 1; + int kode = 2; + int m = 1; + int nz = 0; + int ierr = 0; + + double[] cyhr = new double[n]; + double[] cyhi = new double[n]; + for (int i = 0; i < n; i++) + { + cyhr[i] = double.NaN; + cyhi[i] = double.NaN; + } + + int sign = 1; + if (v < 0) + { + v = -v; + sign = -1; + } + + var amos = new AmosHelper(); + amos.zbesh(z.Real, z.Imaginary, v, kode, m, n, cyhr, cyhi, ref nz, ref ierr); + Complex cyh = new Complex(cyhr[0], cyhi[0]); + + if (sign == -1) + { + cyh = Rotate(cyh, v); + } + + return cyh; + } + #endregion #region HankelH2 + // Returns H2(v, z) public Complex Cbesh2(double v, Complex z) { if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) @@ -581,6 +913,51 @@ namespace MathNet.Numerics return cyh; } + // Returns Exp(z * j) * H2(n, z) where j = Sqrt(-1) + public Complex ScaledCbesh2(double v, Complex z) + { + if (double.IsNaN(v) || double.IsNaN(z.Real) || double.IsNaN(z.Imaginary)) + { + return new Complex(double.NaN, double.NaN); + } + + if (v == 0 && z.Real == 0 && z.Imaginary == 0) + { + return new Complex(double.NaN, double.NaN); // ComplexInfinity + } + + int n = 1; + int kode = 2; + int m = 2; + int nz = 0; + int ierr = 0; + + double[] cyhr = new double[n]; + double[] cyhi = new double[n]; + for (int i = 0; i < n; i++) + { + cyhr[i] = double.NaN; + cyhi[i] = double.NaN; + } + + int sign = 1; + if (v < 0) + { + v = -v; + sign = -1; + } + + var amos = new AmosHelper(); + amos.zbesh(z.Real, z.Imaginary, v, kode, m, n, cyhr, cyhi, ref nz, ref ierr); + Complex cyh = new Complex(cyhr[0], cyhi[0]); + + if (sign == -1) + { + cyh = Rotate(cyh, -v); + } + return cyh; + } + #endregion #region utilities diff --git a/src/Numerics/SpecialFunctions/Bessel.cs b/src/Numerics/SpecialFunctions/Bessel.cs index 054e758b..64842373 100644 --- a/src/Numerics/SpecialFunctions/Bessel.cs +++ b/src/Numerics/SpecialFunctions/Bessel.cs @@ -12,97 +12,130 @@ namespace MathNet.Numerics public static partial class SpecialFunctions { /// - /// Bessel function of the first kind + /// Bessel function of the first kind, J(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * J(v, z) where y = z.Imaginary. ///

- /// The order of the Bessel function + /// The order of the Bessel function /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static Complex BesselJ(double n, Complex z) + public static Complex BesselJ(double v, Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cbesj(n, z); + return (expScaled) ? amos.ScaledCbesj(v, z) : amos.Cbesj(v, z); } /// - /// Bessel function of the first kind + /// Bessel function of the first kind, J(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * J(v, z) where y = z.Imaginary. ///

- /// The order of the Bessel function - /// The value to compute the Bessel function of. + /// The order of the Bessel function + /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static double BesselJ(double n, double x) + public static double BesselJ(double v, double z, bool expScaled = false) { - return BesselJ(n, new Complex(x, 0)).Real; + var amos = new AmosWrapper(); + return (expScaled) ? amos.ScaledCbesj(v, z) : amos.Cbesj(v, z); } /// - /// Bessel function of the second kind + /// Bessel function of the second kind, Y(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * Y(v, z) where y = z.Imaginary. ///

- /// The order of the Bessel function + /// The order of the Bessel function /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static Complex BesselY(double n, Complex z) + public static Complex BesselY(double v, Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cbesy(n, z); + return (expScaled) ? amos.ScaledCbesy(v, z) : amos.Cbesy(v, z); } /// - /// Bessel function of the second kind + /// Bessel function of the second kind, Y(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * Y(v, z) where y = z.Imaginary. ///

- /// The order of the Bessel function - /// The value to compute the Bessel function of. + /// The order of the Bessel function + /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static double BesselY(double n, double x) + public static double BesselY(double v, double z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.CbesyReal(n, x); + return (expScaled) ? amos.ScaledCbesy(v, z) : amos.Cbesy(v, z); } /// - /// Modified Bessel function of the first kind, of order n + /// Modified Bessel function of the first kind, I(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(x)) * I(v, z) where x = z.Real. ///

- /// The order of the Bessel function + /// The order of the Bessel function /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static Complex BesselI(double n, Complex z) + public static Complex BesselI(double v, Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cbesi(n, z); + return (expScaled) ? amos.ScaledCbesi(v, z) : amos.Cbesi(v, z); } /// - /// Modified Bessel function of the first kind, of order n + /// Modified Bessel function of the first kind, I(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(x)) * I(v, z) where x = z.Real. ///

- /// The order of the Bessel function - /// The value to compute the Bessel function of. + /// The order of the Bessel function + /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static double BesselI(double n, double x) + public static double BesselI(double v, double z, bool expScaled = false) { - return BesselI(n, new Complex(x, 0)).Real; + if (expScaled) + { + var amos = new AmosWrapper(); + return amos.ScaledCbesi(v, z); + } + else + { + return BesselI(v, new Complex(z, 0), expScaled).Real; + } } /// - /// Modified Bessel function of the second kind + /// Modified Bessel function of the second kind, K(v, z). + ///

+ /// If expScaled is true, returns Exp(z) * K(v, z). ///

- /// The order of the Bessel function + /// The order of the Bessel function /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static Complex BesselK(double n, Complex z) + public static Complex BesselK(double v, Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cbesk(n, z); + return (expScaled) ? amos.ScaledCbesk(v, z) : amos.Cbesk(v, z); } /// - /// Modified Bessel function of the second kind + /// Modified Bessel function of the second kind, K(v, z). + ///

+ /// If expScaled is true, returns Exp(z) * K(v, z). ///

- /// The order of the Bessel function - /// The value to compute the Bessel function of. + /// The order of the Bessel function + /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Bessel function /// - public static double BesselK(double n, double x) + public static double BesselK(double v, double z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.CbeskReal(n, x); + return (expScaled) ? amos.ScaledCbesk(v, z) : amos.Cbesk(v, z); } } } diff --git a/src/Numerics/SpecialFunctions/Hankel.cs b/src/Numerics/SpecialFunctions/Hankel.cs index 561a8317..970976e0 100644 --- a/src/Numerics/SpecialFunctions/Hankel.cs +++ b/src/Numerics/SpecialFunctions/Hankel.cs @@ -12,49 +12,61 @@ namespace MathNet.Numerics public static partial class SpecialFunctions { /// - /// Hankel function of the first kind + /// Hankel function of the first kind, H1(n, z). + ///

+ /// If expScaled is true, returns Exp(-z * j) * H1(n, z) where j = Sqrt(-1). ///

/// The order of the Bessel function /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Hankel function /// - public static Complex HankelH1(double n, Complex z) + public static Complex HankelH1(double n, Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cbesh1(n, z); + return (expScaled) ? amos.ScaledCbesh1(n, z) : amos.Cbesh1(n, z); } /// - /// Hankel function of the first kind + /// Hankel function of the first kind, H1(n, z). + ///

+ /// If expScaled is true, returns Exp(-z * j) * H1(n, z) where j = Sqrt(-1). ///

/// The order of the Bessel function - /// The value to compute the Bessel function of. + /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Hankel function /// - public static double HankelH1(double n, double x) + public static double HankelH1(double n, double z, bool expScaled = false) { - return HankelH1(n, new Complex(x, 0)).Real; + return HankelH1(n, new Complex(z, 0), expScaled).Real; } /// - /// Hankel function of the second kind + /// Hankel function of the second kind, H2(n, z). + ///

+ /// If expScaled is true, returns Exp(z * j) * H2(n, z) where j = Sqrt(-1). ///

/// The order of the Hankel function /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Hankel function /// - public static Complex HankelH2(double n, Complex z) + public static Complex HankelH2(double n, Complex z, bool expScaled = false) { var amos = new AmosWrapper(); - return amos.Cbesh2(n, z); + return (expScaled) ? amos.ScaledCbesh2(n, z) :amos.Cbesh2(n, z); } /// - /// Hankel function of the second kind + /// Hankel function of the second kind, H2(n, z). + ///

+ /// If expScaled is true, returns Exp(z * j) * H2(n, z) where j = Sqrt(-1). ///

/// The order of the Bessel function - /// The value to compute the Bessel function of. + /// The value to compute the Bessel function of. + /// If true, returns exponentially-scaled Hankel function /// - public static double HankelH2(double n, double x) + public static double HankelH2(double n, double z, bool expScaled = false) { - return HankelH2(n, new Complex(x, 0)).Real; + return HankelH2(n, new Complex(z, 0), expScaled).Real; } } } diff --git a/src/Numerics/SpecialFunctions/SphericalBessel.cs b/src/Numerics/SpecialFunctions/SphericalBessel.cs index 52cfa333..7cd22fa8 100644 --- a/src/Numerics/SpecialFunctions/SphericalBessel.cs +++ b/src/Numerics/SpecialFunctions/SphericalBessel.cs @@ -12,55 +12,67 @@ namespace MathNet.Numerics public static partial class SpecialFunctions { /// - /// Spherical Bessel function of the first kind + /// Spherical Bessel function of the first kind, j(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * j(v, z) where y = z.Imaginary. ///

- /// The order of the spherical Bessel function + /// The order of the spherical Bessel function /// The value to compute the spherical Bessel function of. + /// If true, returns exponentially-scaled spherical Bessel function /// - public static Complex SphericalBesselJ(double n, Complex z) + public static Complex SphericalBesselJ(double v, Complex z, bool expScaled = false) { const double rthpi = 1.2533141373155002512; //sqrt(pi/2) - return rthpi * BesselJ(n + 0.5, z) / Complex.Sqrt(z); + return rthpi * BesselJ(v + 0.5, z, expScaled) / Complex.Sqrt(z); } /// - /// Spherical Bessel function of the first kind + /// Spherical Bessel function of the first kind, j(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * j(v, z) where y = z.Imaginary. ///

- /// The order of the spherical Bessel function - /// The value to compute the spherical Bessel function of. + /// The order of the spherical Bessel function + /// The value to compute the spherical Bessel function of. + /// If true, returns exponentially-scaled spherical Bessel function /// - public static double SphericalBesselJ(double n, double x) + public static double SphericalBesselJ(double v, double z, bool expScaled = false) { const double rthpi = 1.2533141373155002512; //sqrt(pi/2) - return rthpi * BesselJ(n + 0.5, x) / Math.Sqrt(x); + return rthpi * BesselJ(v + 0.5, z, expScaled) / Math.Sqrt(z); } /// - /// Spherical Bessel function of the second kind + /// Spherical Bessel function of the second kind, y(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * y(v, z) where y = z.Imaginary. ///

- /// The order of the spherical Bessel function + /// The order of the spherical Bessel function /// The value to compute the spherical Bessel function of. + /// If true, returns exponentially-scaled spherical Bessel function /// - public static Complex SphericalBesselY(double n, Complex z) + public static Complex SphericalBesselY(double v, Complex z, bool expScaled = false) { const double rthpi = 1.2533141373155002512; //sqrt(pi/2) - return rthpi * BesselY(n + 0.5, z) / Complex.Sqrt(z); + return rthpi * BesselY(v + 0.5, z, expScaled) / Complex.Sqrt(z); } /// - /// Spherical Bessel function of the second kind + /// Spherical Bessel function of the second kind, y(v, z). + ///

+ /// If expScaled is true, returns Exp(-Abs(y)) * y(v, z) where y = z.Imaginary. ///

- /// The order of the spherical Bessel function - /// The value to compute the spherical Bessel function of. + /// The order of the spherical Bessel function + /// The value to compute the spherical Bessel function of. + /// If true, returns exponentially-scaled spherical Bessel function /// - public static double SphericalBesselY(double n, double x) + public static double SphericalBesselY(double v, double z, bool expScaled = false) { const double rthpi = 1.2533141373155002512; //sqrt(pi/2) - return rthpi * BesselY(n + 0.5, x) / Math.Sqrt(x); + return rthpi * BesselY(v + 0.5, z, expScaled) / Math.Sqrt(z); } } }