/// <summary> /// Returns J{v}(x) for integer v /// </summary> /// <param name="v"></param> /// <param name="x"></param> /// <returns></returns> public static double JN(double v, double x) { Debug.Assert(Math2.IsInteger(v)); // For integer orders only, we can use two identities: // #1: J{-n}(x) = (-1)^n * J{n}(x) // #2: J{n}(-x) = (-1)^n * J{n}(x) double sign = 1; if (v < 0) { v = -v; if (Math2.IsOdd(v)) { sign = -sign; } } if (x < 0) { x = -x; if (Math2.IsOdd(v)) { sign = -sign; } } Debug.Assert(v >= 0 && x >= 0); if (v > int.MaxValue) { Policies.ReportNotImplementedError("BesselJ(v: {0}): Large integer values not yet implemented", v); return(double.NaN); } int n = (int)v; // // Special cases: // if (n == 0) { return(sign * J0(x)); } if (n == 1) { return(sign * J1(x)); } // n >= 2 Debug.Assert(n >= 2); if (x == 0) { return(0); } if (x < 5 || (v > x * x / 4)) { return(sign * J_SmallArg(v, x)); } // if v > MinAsymptoticV, use the asymptotics const int MinAsymptoticV = 7; // arbitrary constant to reduce iterations if (v > MinAsymptoticV) { double Jv; DoubleX Yv; if (JY_TryAsymptotics(v, x, out Jv, out Yv, true, false)) { return(sign * Jv); } } // v < abs(x), forward recurrence stable and usable // v >= abs(x), forward recurrence unstable, use Miller's algorithm if (v < x) { // use forward recurrence double prev = J0(x); double current = J1(x); return(sign * Recurrence.ForwardJY(1.0, x, n - 1, current, prev).JYvpn); } else { // Steed is somewhat more accurate when n gets large if (v >= 200) { var(J, Y) = JY_Steed(n, x, true, false); return(J); } // J{n+1}(x) / J{n}(x) var(fv, s) = J_CF1(n, x); var(Jvmn, Jvmnp1, scale) = Recurrence.BackwardJY_B(n, x, n, s, fv * s); // scale the result double Jv = (J0(x) / Jvmn); Jv = Math2.Ldexp(Jv, -scale); return((s * sign) * Jv); // normalization } }
/// <summary> /// Computes J{v}(x), Y{v}(x) using a combination of asymptotic approximation and recurrence /// </summary> /// <param name="v"></param> /// <param name="x"></param> /// <param name="needJ"></param> /// <param name="needY"></param> /// <returns></returns> static (double J, DoubleX Y) JY_AsymRecurrence(double v, double x, bool needJ, bool needY) { Debug.Assert(v >= 0 && x >= 1, "Requires positive values for v,x"); Debug.Assert(v < int.MaxValue, "v too large: v = " + v); var J = double.NaN; var Y = DoubleX.NaN; int nPos = (int)Math.Floor(v); double uPos = v - nPos; // Using Hankel, find: // J{v-Floor(v)}(x) and J{v-Floor(v)+1}(x) // Y{v-Floor(v)}(x) and Y{v-Floor(v)+1}(x) // then use recurrence to find J{v}(x), Y{v}(x) double u0, u1;; int n; if (x >= 9) { // set the start of the recurrence near sqrt(x) double maxV = Math.Floor(Math.Sqrt(x)); u1 = (maxV - 1) + uPos; u0 = u1 - 1; n = (int)Math.Floor(v - u1 + 0.5); Debug.Assert(n >= 0); } else { u0 = uPos; u1 = uPos + 1; n = nPos - 1; } Debug.Assert(x >= HankelAsym.JYMinX(u1), "x is too small for HankelAsym"); var(Ju, Yu) = HankelAsym.JY(u0, x); var(Jup1, Yup1) = HankelAsym.JY(u1, x); if (needJ) { if (v < x) { J = Recurrence.ForwardJY(u1, x, n, Jup1, Ju).JYvpn; } else { // Use fv = J{v+1}(x) / J{v}(x) // and backward recurrence to find (J{v-n+1}/J{v-n}) var(fv, s) = J_CF1(v, x); var(Jvmn, Jvmnp1, scale) = Recurrence.BackwardJY_B(v, x, n, s, fv * s); var Jv = Math2.Ldexp(Jup1 / Jvmn, -scale); J = s * Jv; // normalization } } if (needY) { var(Yv, Yvm1, YScale) = Recurrence.ForwardJY_B(u1, x, n, Yup1, Yu); Y = DoubleX.Ldexp(Yv, YScale); } return(J, Y); }