Ejemplo n.º 1
0
        /// <summary>
        /// Try to use asymptotics to generate the result
        /// </summary>
        /// <param name="v"></param>
        /// <param name="x"></param>
        /// <param name="J"></param>
        /// <param name="Y"></param>
        /// <param name="needJ"></param>
        /// <param name="needY"></param>
        /// <returns></returns>
        public static bool JY_TryAsymptotics(double v, double x, out double J, out DoubleX Y, bool needJ, bool needY)
        {
            J = double.NaN;
            Y = DoubleX.NaN;

            // Try asymptotics directly:

            if (x > v)
            {
                // x > v*v
                if (x >= HankelAsym.JYMinX(v))
                {
                    var result = HankelAsym.JY(v, x);
                    if (needJ)
                    {
                        J = result.J;
                    }
                    if (needY)
                    {
                        Y = result.Y;
                    }
                    return(true);
                }

                // Try Asymptotic Phase for x > 47v
                if (x >= MagnitudePhase.MinX(v))
                {
                    var result = MagnitudePhase.BesselJY(v, x);
                    if (needJ)
                    {
                        J = result.J;
                    }
                    if (needY)
                    {
                        Y = result.Y;
                    }
                    return(true);
                }
            }

            if (UniformAsym.IsJYPrecise(v, x))
            {
                var(Jv, Yv) = UniformAsym.JY(v, x);
                if (needJ)
                {
                    J = Jv;
                }
                if (needY)
                {
                    Y = Yv;
                }
                return(true);
            }

            // Try asymptotics with recurrence
            if (x > v && x >= HankelAsym.JYMinX(v - Math.Floor(v) + 1))
            {
                var(Jv, Yv) = JY_AsymRecurrence(v, x, needJ, needY);
                if (needJ)
                {
                    J = Jv;
                }
                if (needY)
                {
                    Y = Yv;
                }
                return(true);
            }

            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Compute J{v}(x) and Y{v}(x)
        /// </summary>
        /// <param name="v"></param>
        /// <param name="x"></param>
        /// <param name="needJ"></param>
        /// <param name="needY"></param>
        /// <returns></returns>
        public static (double J, DoubleX Y) JY(double v, double x, bool needJ, bool needY)
        {
            Debug.Assert(needJ || needY);

            // uses  Steed's method
            // see Barnett et al, Computer Physics Communications, vol 8, 377 (1974)

            // set [out] parameters
            double  J = double.NaN;
            DoubleX Y = DoubleX.NaN;

            // check v first so that there are no integer throws later
            if (Math.Abs(v) > int.MaxValue)
            {
                Policies.ReportNotImplementedError("BesselJY(v: {0}): Large |v| > int.MaxValue not yet implemented", v);
                return(J, Y);
            }


            if (v < 0)
            {
                v = -v;

                if (Math2.IsInteger(v))
                {
                    // for integer orders only, we can use the following identities:
                    //      J{-n}(x) = (-1)^n * J{n}(x)
                    //      Y{-n}(x) = (-1)^n * Y{n}(x)

                    if (Math2.IsOdd(v))
                    {
                        var(JPos, YPos) = JY(v, x, needJ, needY);

                        if (needJ)
                        {
                            J = -JPos;
                        }
                        if (needY)
                        {
                            Y = -YPos;
                        }

                        return(J, Y);
                    }
                }
                if (v - Math.Floor(v) == 0.5)
                {
                    Debug.Assert(v >= 0);

                    // use reflection rule:
                    // for integer m >= 0
                    // J{-(m+1/2)}(x) = (-1)^(m+1) * Y{m+1/2}(x)
                    // Y{-(m+1/2)}(x) = (-1)^m * J{m+1/2}(x)

                    // call the general bessel functions with needJ and needY reversed
                    var(JPos, YPos) = JY(v, x, needY, needJ);

                    double m     = v - 0.5;
                    bool   isOdd = Math2.IsOdd(m);

                    if (needJ)
                    {
                        double y = (double)YPos;
                        J = isOdd ? y : -y;
                    }
                    if (needY)
                    {
                        Y = isOdd ? -JPos : JPos;
                    }

                    return(J, Y);
                }
                else
                {
                    // use reflection rule:
                    // J{-v}(x) = cos(pi*v)*J{v}(x) - sin(pi*v)*Y{v}(x)
                    // Y{-v}(x) = sin(pi*v)*J{v}(x) + cos(pi*v)*Y{v}(x)

                    var(JPos, YPos) = JY(v, x, true, true);

                    double cp = Math2.CosPI(v);
                    double sp = Math2.SinPI(v);

                    J = cp * JPos - (double)(sp * YPos);
                    Y = sp * JPos + cp * YPos;

                    return(J, Y);
                }
            }

            // both x and v are positive from here
            Debug.Assert(x >= 0 && v >= 0);

            if (x == 0)
            {
                // For v > 0
                if (needJ)
                {
                    J = 0;
                }
                if (needY)
                {
                    Y = DoubleX.NegativeInfinity;
                }
                return(J, Y);
            }

            int    n = (int)Math.Floor(v + 0.5);
            double u = v - n;                              // -1/2 <= u < 1/2

            // is it an integer?
            if (u == 0)
            {
                if (v == 0)
                {
                    if (needJ)
                    {
                        J = J0(x);
                    }
                    if (needY)
                    {
                        Y = Y0(x);
                    }
                    return(J, Y);
                }

                if (v == 1)
                {
                    if (needJ)
                    {
                        J = J1(x);
                    }
                    if (needY)
                    {
                        Y = Y1(x);
                    }
                    return(J, Y);
                }

                // for integer order only
                if (needY && x < DoubleLimits.RootMachineEpsilon._2)
                {
                    Y = YN_SmallArg(n, x);
                    if (!needJ)
                    {
                        return(J, Y);
                    }
                    needY = !needY;
                }
            }


            if (needJ && ((x < 5) || (v > x * x / 4)))
            {
                // always use the J series if we can
                J = J_SmallArg(v, x);
                if (!needY)
                {
                    return(J, Y);
                }
                needJ = !needJ;
            }

            if (needY && x <= 2)
            {
                // J should have already been solved above
                Debug.Assert(!needJ);

                // Evaluate using series representations.
                // Much quicker than Y_Temme below.
                // This is particularly important for x << v as in this
                // area Y_Temme may be slow to converge, if it converges at all.

                // for non-integer order only
                if (u != 0)
                {
                    if ((x < 1) && (Math.Log(DoubleLimits.MachineEpsilon / 2) > v * Math.Log((x / 2) * (x / 2) / v)))
                    {
                        Y = Y_SmallArgSeries(v, x);
                        return(J, Y);
                    }
                }

                // Use Temme to find Yu where |u| <= 1/2, then use forward recurrence for Yv

                var(Yu, Yu1) = Y_Temme(u, x);
                var(Yvpn, Yvpnm1, YScale) = Recurrence.ForwardJY_B(u + 1, x, n, Yu1, Yu);
                Y = DoubleX.Ldexp(Yvpnm1, YScale);
                return(J, Y);
            }

            Debug.Assert(x > 2 && v >= 0);

            // Try asymptotics directly:

            if (x > v)
            {
                // x > v*v
                if (x >= HankelAsym.JYMinX(v))
                {
                    var result = HankelAsym.JY(v, x);
                    if (needJ)
                    {
                        J = result.J;
                    }
                    if (needY)
                    {
                        Y = result.Y;
                    }
                    return(J, Y);
                }

                // Try Asymptotic Phase for x > 47v
                if (x >= MagnitudePhase.MinX(v))
                {
                    var result = MagnitudePhase.BesselJY(v, x);
                    if (needJ)
                    {
                        J = result.J;
                    }
                    if (needY)
                    {
                        Y = result.Y;
                    }
                    return(J, Y);
                }
            }

            // fast and accurate within a limited range of v ~= x
            if (UniformAsym.IsJYPrecise(v, x))
            {
                var(Jv, Yv) = UniformAsym.JY(v, x);
                if (needJ)
                {
                    J = Jv;
                }
                if (needY)
                {
                    Y = Yv;
                }
                return(J, Y);
            }

            // Try asymptotics with recurrence:
            if (x > v && x >= HankelAsym.JYMinX(v - Math.Floor(v) + 1))
            {
                var(Jv, Yv) = JY_AsymRecurrence(v, x, needJ, needY);
                if (needJ)
                {
                    J = Jv;
                }
                if (needY)
                {
                    Y = Yv;
                }
                return(J, Y);
            }

            // Use Steed's Method
            var(SteedJv, SteedYv) = JY_Steed(v, x, needJ, needY);
            if (needJ)
            {
                J = SteedJv;
            }
            if (needY)
            {
                Y = SteedYv;
            }
            return(J, Y);
        }
Ejemplo n.º 3
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);
        }