Example #1
0
        /// <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
            }
        }
Example #2
0
        /// <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);
        }