Пример #1
0
        /// <summary>
        /// Returns the sum of a hypergeometric series 3F1. 
        /// <para>Sum3F1 = addend + Σ(( (a1)_n * (a2)_n * (a3)_n)/(b1)_n * (z^n/n!)) n={0,∞}</para>
        /// </summary>
        /// <param name="a1">First numerator</param>
        /// <param name="a2">Second numerator</param>
        /// <param name="a3">Third numerator</param>
        /// <param name="b1">First denominator. Requires b1 > 0</param>
        /// <param name="z">Argument</param>
        /// <param name="addend">The addend to the series</param>
        /// <returns>
        /// The sum of the series, or NaN if the series does not converge
        /// within the policy maximum number of iterations 
        /// </returns>
        public static double Sum3F1(double a1, double a2, double a3, double b1, double z, double addend = 0)
        {
            if ((double.IsNaN(a1) || double.IsInfinity(a1))
            || (double.IsNaN(a2) || double.IsInfinity(a2))
            || (double.IsNaN(a3) || double.IsInfinity(a3))
            || (double.IsNaN(z) || double.IsInfinity(z))
            || (double.IsNaN(b1) || double.IsInfinity(b1))
            || double.IsNaN(addend)) {
                Policies.ReportDomainError("Sum3F1(a1: {0}, a2: {1}, a3: {2}, b1: {3}, z: {4}, addend: {5}): Requires finite arguments", a1, a2, a3, b1, z, addend);
                return double.NaN;
            }
            if (b1 <= 0 && Math2.IsInteger(b1)) {
                Policies.ReportDomainError("Sum3F1(a1: {0}, a2: {1}, a3: {2}, b1: {3}, z: {4}, addend: {5}): Requires b1 is not zero or a negative integer", a1, a2, a3, b1, z, addend);
                return double.NaN;
            }

            double sum = 1.0 + addend;

            if (z == 0)
                return sum;
            if (a1 == b1)
                return Sum2F0(a2, a3, z, addend);
            if (a2 == b1)
                return Sum2F0(a1, a3, z, addend);
            if (a3 == b1)
                return Sum2F0(a1, a2, z, addend);
#if false
            // TODO:
            if (a1 == 1)
                return Sum3F1_A1(a2, a3, b1, z, addend);
            if (a2 == 1)
                return Sum3F1_A1(a1, a3, b1, z, addend);
            if (a3 == 1)
                return Sum3F1_A1(a1, a2, b1, z, addend);
#endif

            double term = 1.0;
            int n = 0; 
            for (; n < Policies.MaxSeriesIterations; n++) {

                double prevSum = sum;
                term *= (z / (n + 1)) * ((a1 + n) / (b1 + n)) * (a2 + n) * (a3 + n);
                sum += term;

#if CMP_FLOAT
                if (Math.Abs(term) <= Math.Abs(prevSum) * Policies.SeriesTolerance)
                    return sum;
#else
                if (sum == prevSum)
                    return sum;
#endif
            }

            Policies.ReportConvergenceError("Sum3F1(a1: {0}, a2: {1}, a3: {2}, b1: {3}, z: {4}, addend: {5}): No convergence after {6} iterations", a1, a2, a3, b1, z, addend, n);
            return double.NaN;
        }
Пример #2
0
        /// <summary>
        /// Returns the sum of a hypergeometric series 1F2. 
        /// <para>Sum2F1 = addend + Σ( ((a1)_n)/((b1)_n * (b2)_n) * (z^n/n!)) n={0,∞}</para>
        /// </summary>
        /// <param name="a1">First numerator</param>
        /// <param name="b1">First denominator. Requires b1 &gt; 0</param>
        /// <param name="b2">Second denominator. Requires b2 &gt; 0</param>
        /// <param name="z">Argument</param>
        /// <param name="addend">The addend to the series</param>
        /// <returns>
        /// The sum of the series, or NaN if the series does not converge
        /// within the policy maximum number of iterations 
        /// </returns>
        public static double Sum1F2(double a1, double b1, double b2, double z, double addend = 0)
        {
            if ((double.IsNaN(a1) || double.IsInfinity(a1))
            || (double.IsNaN(z) || double.IsInfinity(z))
            || (double.IsNaN(b1) || double.IsInfinity(b1))
            || (double.IsNaN(b2) || double.IsInfinity(b2))
            || double.IsNaN(addend)) {
                Policies.ReportDomainError("Sum1F2(a1: {0}, b1: {1}, b2: {2}, z: {3}, addend: {4}): Requires finite arguments", a1, b1, b2, z, addend);
                return double.NaN;
            }
            if ((b1 <= 0 && Math2.IsInteger(b1))
                || (b2 <= 0 && Math2.IsInteger(b2))) {
                Policies.ReportDomainError("Sum1F2(a1: {0}, b1: {1}, b2: {2}, z: {3}, addend: {4}): Requires b1, b2 are not zero or negative integers", a1, b1, b2, z, addend);
                return double.NaN;
            }

            double sum = 1.0 + addend;

            if (z == 0)
                return sum;
            if (a1 == b1)
                return Sum0F1(b2, z, addend);
            if (a1 == b2)
                return Sum0F1(b1, z, addend);
            if (a1 == 1)
                return Sum1F2_A1(b1, b2, z, addend);

            double term = 1.0;
            int n = 0; 
            for (; n < Policies.MaxSeriesIterations; n++) {

                double prevSum = sum;
                term *= (z / (n + 1)) * (((a1 + n) / (b1 + n)) / (b2 + n));
                sum += term;

#if CMP_FLOAT
                if (Math.Abs(term) <= Math.Abs(prevSum) * Policies.SeriesTolerance)
                    return sum;
#else
                if (sum == prevSum)
                    return sum;
#endif

            }

            Policies.ReportConvergenceError("Sum1F2(a1: {0}, b1: {1}, b2: {2}, z: {3}, addend: {4}): No convergence after {0} iterations", a1, b1, b2, z, addend, n);
            return double.NaN;
        }
Пример #3
0
        //
        // Series form for BesselY as z -> 0, 
        // see: http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/01/0003/
        // This series is only useful when the second term is small compared to the first
        // otherwise we get catestrophic cancellation errors.
        //
        // Approximating tgamma(v) by v^v, and assuming |tgamma(-z)| < eps we end up requiring:
        // eps/2 * v^v(x/2)^-v > (x/2)^v or Math.Log(eps/2) > v Math.Log((x/2)^2/v)
        //


        /// <summary>
        /// Series form for Y{v}(x) as z -&gt; 0 and v is not an integer
        /// <para>Y{v}(z) = (-((z/2)^v Cos(πv) Γ(-v))/π)) * 0F1(; 1+v; -z^2/4) - ((z/2)^-v Γ(v))/π) * 0F1(; 1-v; -z^2/4)</para>
        /// </summary>
        /// <param name="v"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        /// <seealso href="http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/26/01/02/0001/"/>
        public static DoubleX Y_SmallArgSeries(double v, double x)
        {
            Debug.Assert(v >= 0 && x >= 0);
            Debug.Assert( !Math2.IsInteger(v), "v cannot be an integer");


            DoubleX powDivGamma;
            double lnp = v * Math.Log(x / 2);
            if (v > DoubleLimits.MaxGamma || lnp < DoubleLimits.MinLogValue || lnp > DoubleLimits.MaxLogValue) {
                powDivGamma = DoubleX.Exp(lnp - Math2.Lgamma(v));
            } else {
                DoubleX p = Math.Pow(x / 2, v);
                DoubleX gam = Math2.Tgamma(v);
                powDivGamma = p / gam;
            }


            // Series 1: -((z/2)^-v Γ(v))/π) * 0F1(; 1-v; -z^2/4)

            double s1 = HypergeometricSeries.Sum0F1(1 - v, -x * x / 4);
            DoubleX result1 = -(s1/Math.PI)/ powDivGamma;

            // Series2: -((z/2)^v Cos(πv) Γ(-v))/π)) * 0F1(; 1+v; -z^2/4)
            // using the reflection formula: Γ(-v) = -π/(Γ(v) * v * Sin(π * v)) 
            // prefix = (z/2)^v * Cos(π * v)/(Γ(v) * v * Sin(π * v)) 
            // prefix = (z/2)^v * Cot(π * v) / (Γ(v) * v) 

            DoubleX result2 = DoubleX.Zero;
            double cot = Math2.CotPI(v);
            if (cot != 0) {
                double s2 = HypergeometricSeries.Sum0F1(v + 1, -x * x / 4);
                result2 = powDivGamma * cot * s2 / v; // Do this all in DoubleX
            }

            return (result1 - result2);
        }
Пример #4
0
        /// <summary>
        /// Returns the sum of a hypergeometric series PFQ, which has a variable number of numerators and denominators. 
        /// <para> PFQ = addend + Σ(( Prod(a[j]_n)/Prod(b[j])_n * (z^n/n!)) n={0,∞}</para>
        /// </summary>
        /// <param name="a">The array of numerators</param>
        /// <param name="b">The array of denominators. (b != 0 or b != negative integer)</param>
        /// <param name="z">Argument</param>
        /// <param name="addend">The addend to the series</param>
        /// <returns>
        /// The sum of the series, or NaN if the series does not converge
        /// within the policy maximum number of iterations 
        /// </returns>
        public static double SumPFQ(double[] a, double[] b, double z, double addend = 0)
        {
            if ( (a == null || b == null)
                || (double.IsNaN(z) || double.IsInfinity(z))
                || double.IsNaN(addend)) {
                string aStr = (a == null) ? "null" : a.ToString();
                string bStr = (b == null) ? "null" : b.ToString();
                Policies.ReportDomainError("SumPFQ(a: {0}; b: {1}, z: {2}, addend: {3}): Requires finite non-null arguments", aStr, bStr, z, addend);
                return double.NaN;
            }

            if (a.Length == 0 && b.Length == 0)
                return Sum0F0(z, addend);

            // check for infinities or non-positive integer b

            bool hasBadParameter = false;
            for (int i = 0; i < a.Length; i++) {
                if (double.IsInfinity(a[i])) {
                    hasBadParameter = true;
                    break;
                }
            }

            if (!hasBadParameter) {
                for (int i = 0; i < b.Length; i++) {
                    if (double.IsInfinity(b[i]) || (b[i] <= 0 && Math2.IsInteger(b[i]))) {
                        hasBadParameter = true;
                        break;
                    }


                }
            }

            if (hasBadParameter) {
                Policies.ReportDomainError("SumPFQ(a: {0}; b: {1}, z: {2}, addend: {3}): Requires finite arguments and b not zero or a negative integer", a, b, z, addend);
                return double.NaN;
            }

            double sum = 1.0 + addend;

            if (z == 0)
                return sum;

            double term = 1.0;
            int n = 0; 
            for (; n < Policies.MaxSeriesIterations; n++) {


                double term_part = (z / (n + 1));

                // use a/b where we can for max(a.Length, b.Length)

                int j = 0;
                for (; j < a.Length && j < b.Length; j++) {
                    term_part *= (a[j] + n) / (b[j] + n);
                }

                // otherwise multiply or divide the rest of the factors 
                // either a or b

                for (; j < a.Length; j++) {
                    term_part *= (a[j] + n);
                }

                for (; j < b.Length; j++) {
                    term_part /= (b[j] + n);
                }

                term *= term_part;

                double prevSum = sum;
                sum += term;

#if CMP_FLOAT
                if (Math.Abs(term) <= Math.Abs(prevSum) * Policies.SeriesTolerance)
                    return sum;
#else
                if (sum == prevSum)
                    return sum;
#endif

            }

            Policies.ReportConvergenceError("No convergence after {0} iterations", n);
            return double.NaN;

        }
Пример #5
0
        /// <summary>
        /// Simultaneously compute I{v}(x) and K{v}(x)
        /// </summary>
        /// <param name="v"></param>
        /// <param name="x"></param>
        /// <param name="needI"></param>
        /// <param name="needK"></param>
        /// <returns>A tuple of (I, K). If needI == false or needK == false, I = NaN or K = NaN  respectively</returns>
        public static (double I, double K) IK(double v, double x, bool needI, bool needK)
        {
            Debug.Assert(needI || needK, "NeedI and NeedK cannot both be false");

            // set initial values for parameters
            double I = double.NaN;
            double K = double.NaN;

            // check v first so that there are no integer throws later
            if (Math.Abs(v) > int.MaxValue)
            {
                Policies.ReportNotImplementedError("BesselIK(v: {0}, x: {1}): Requires |v| <= {2}", v, x, int.MaxValue);
                return(I, K);
            }


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

                // for integer orders only, we can use the following identities:
                //  I{-n}(x) = I{n}(v)
                //  K{-n}(x) = K{n}(v)
                // for any v, use reflection rule:
                //  I{-v}(x) = I{v}(x) + (2/PI) * sin(pi*v)*K{v}(x)
                //  K{-v}(x) = K{v}(x)

                if (needI && !Math2.IsInteger(v))
                {
                    var(IPos, KPos) = IK(v, x, true, true);

                    I = IPos + (2 / Math.PI) * Math2.SinPI(v) * KPos;
                    if (needK)
                    {
                        K = KPos;
                    }
                    return(I, K);
                }
            }

            if (x < 0)
            {
                Policies.ReportDomainError("BesselIK(v: {0}, x: {1}): Complex result not supported. Requires x >= 0", v, x);
                return(I, K);
            }

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

            if (x == 0)
            {
                if (needI)
                {
                    I = (v == 0) ? 1.0 : 0.0;
                }
                if (needK)
                {
                    K = double.PositiveInfinity;
                }
                return(I, K);
            }

            if (needI && (x < 2 || 3 * (v + 1) > x * x))
            {
                I     = I_SmallArg(v, x);
                needI = false;
                if (!needK)
                {
                    return(I, K);
                }
            }

            // Hankel is fast, and reasonably accurate.
            // at x == 32, it will converge in about 15 iterations
            if (x >= HankelAsym.IKMinX(v))
            {
                if (needK)
                {
                    K = HankelAsym.K(v, x);
                }
                if (needI)
                {
                    I = HankelAsym.I(v, x);
                }
                return(I, K);
            }

            // the uniform expansion is here as a last resort
            // to limit the number of recurrences, but it is less accurate.
            if (UniformAsym.IsIKAvailable(v, x))
            {
                if (needK)
                {
                    K = UniformAsym.K(v, x);
                }
                if (needI)
                {
                    I = UniformAsym.I(v, x);
                }
                return(I, K);
            }


            // K{v}(x) and K{v+1}(x), binary scaled
            var(Kv, Kv1, binaryScale) = K_CF(v, x);
            if (needK)
            {
                K = Math2.Ldexp(Kv, binaryScale);
            }
            if (needI)
            {
                // use the Wronskian relationship

                // Since CF1 is O(x) for x > v, try to weed out obvious overflows
                // Note: I{v+1}(x)/I{v}(x) is in [0, 1].
                // I{0}(713. ...) == MaxDouble
                const double I0MaxX = 713;
                if (x > I0MaxX && x > v)
                {
                    I = Math2.Ldexp(1.0 / (x * (Kv + Kv1)), -binaryScale);
                    if (double.IsInfinity(I))
                    {
                        return(I, K);
                    }
                }

                double W  = 1 / x;
                double fv = I_CF1(v, x);
                I = Math2.Ldexp(W / (Kv * fv + Kv1), -binaryScale);
            }


            return(I, K);
        }
Пример #6
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
            }
        }
Пример #7
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);
        }