コード例 #1
0
        // series near the origin; this is entirely analogous to the Bessel series near the origin
        // it has a corresponding radius of rapid convergence, x < 4 + 2 Sqrt(nu)

        // This is exactly the same as BesselJ_Series with xx -> -xx.
        // We could even factor this out into a common method with an additional parameter.

        private static void ModifiedBesselI_Series(double nu, double x, out double I, out double IP)
        {
            Debug.Assert(x > 0.0);

            double x2 = 0.5 * x;
            double xx = x2 * x2;
            double dI = AdvancedMath.PowerOverFactorial(x2, nu);

            I  = dI;
            IP = nu * dI;
            for (int k = 1; k < Global.SeriesMax; k++)
            {
                double I_old  = I;
                double IP_old = IP;
                dI *= xx / (k * (nu + k));
                I  += dI;
                IP += (2 * k + nu) * dI;
                if ((I == I_old) && (IP == IP_old))
                {
                    IP = IP / x;
                    return;
                }
            }

            throw new NonconvergenceException();
        }
コード例 #2
0
        // Regular Bessel function series about origin
        //   J_{\nu}(x) = (x/2)^{\nu} \sum{k=0}^{\infty} \frac{(-x^2/4)^k}{k! \Gamma(\nu + k + 1)}
        // This can be turned into a series for J' by term-by-term differentiation
        // For nu=0, x~1 it requires ~10 terms, x~4 requires ~17 terms, x~8 requires ~24 terms
        // Since nu appears in the denominator, higher nu converges faster
        // Since first correction term is ~\frac{x^2}{4\nu}, the radius of fast convergence should grow ~2\sqrt{\nu}

        private static void BesselJ_Series(double nu, double x, out double J, out double JP)
        {
            // We divide by x to deal with derivative, so handle x = 0 separately.
            Debug.Assert(x > 0.0);

            // Evaluate the series of J and J', knowing x != 0
            // Note that the J' series is just with J series with teach term having one less power,
            // and each term multipled by the power it has in the J series.
            double x2  = 0.5 * x;
            double x22 = -x2 * x2;
            double dJ  = AdvancedMath.PowerOverFactorial(x2, nu);

            J  = dJ;
            JP = nu * dJ;
            for (int k = 1; k < Global.SeriesMax; k++)
            {
                double J_old  = J;
                double JP_old = JP;
                dJ *= x22 / (k * (nu + k));
                J  += dJ;
                JP += (nu + 2 * k) * dJ;
                if ((J == J_old) && (JP == JP_old))
                {
                    JP = JP / x;
                    return;
                }
            }
            // The J series alone requires 5 ops per term; J' evaulation adds 2 ops per term.
            throw new NonconvergenceException();
        }
コード例 #3
0
        private static double ModifiedBesselI_Series(double nu, double x)
        {
            double x2 = 0.5 * x;
            double xx = x2 * x2;
            double dI = AdvancedMath.PowerOverFactorial(x2, nu);
            double I  = dI;

            for (int k = 1; k < Global.SeriesMax; k++)
            {
                double I_old = I;
                dI = dI * xx / (k * (nu + k));
                I += dI;
                if (I == I_old)
                {
                    return(I);
                }
            }
            throw new NonconvergenceException();
        }
コード例 #4
0
        // **** Real order Bessel functions ****

        // Series development of Bessel J
        //   J_{\nu}(x) = \sum_{k=0}^{\infty} \frac{( )^{\nu + 2k}}{\Gamma(\nu + 2k + 1)}
        // As can be seen by comparing leading term and first correction, this is good for z <~ \max(1 , \sqrt{\nu})

        // For nu=0, it requires 10 terms at x~1.0, 25 terms at x~10.0, but accuracy in the last few digits suffers that far out
        // Gets better for higher nu (for nu=10, only 20 terms are required at x~10.0 and all digits are good), but only with sqrt(nu)

        private static double BesselJ_Series(double nu, double x)
        {
            double z  = 0.5 * x;
            double dJ = AdvancedMath.PowerOverFactorial(z, nu);
            double J  = dJ;
            double zz = -z * z;

            for (int k = 1; k < Global.SeriesMax; k++)
            {
                double J_old = J;
                dJ *= zz / (k * (nu + k));
                J  += dJ;
                if (J == J_old)
                {
                    return(J);
                }
            }
            throw new NonconvergenceException();
        }
コード例 #5
0
        // this is just an integer version of the series we implement below for doubles;
        // having an integer-specific version is slightly faster

        private static double BesselJ_Series(int n, double x)
        {
            Debug.Assert(n >= 0);
            Debug.Assert(x >= 0.0);
            double z  = 0.5 * x;
            double dJ = AdvancedMath.PowerOverFactorial(z, n);
            double J  = dJ;
            double zz = -z * z;

            for (int k = 1; k < Global.SeriesMax; k++)
            {
                double J_old = J;
                dJ *= zz / ((n + k) * k);
                J  += dJ;
                if (J == J_old)
                {
                    return(J);
                }
            }
            throw new NonconvergenceException();
        }
コード例 #6
0
        /// <summary>
        /// Computes the given Bernoulli number.
        /// </summary>
        /// <param name="n">The index of the Bernoulli number to compute, which must be non-negative.</param>
        /// <returns>The Bernoulli number B<sub>n</sub>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative.</exception>
        /// <remarks>
        /// <para>B<sub>n</sub> vanishes for all odd n except n=1. For n about 260 or larger, B<sub>n</sub> overflows a double.</para>
        /// </remarks>
        /// <seealso href="http://en.wikipedia.org/wiki/Bernoulli_number"/>
        /// <seealso href="http://mathworld.wolfram.com/BernoulliNumber.html"/>
        public static double BernoulliNumber(int n)
        {
            if (n < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(n));
            }

            // B_1 is the only odd Bernoulli number.
            if (n == 1)
            {
                return(-1.0 / 2.0);
            }

            // For all other odd arguments, return zero.
            if (n % 2 != 0)
            {
                return(0.0);
            }

            // If the argument is small enough, look up the answer in our stored array.
            int m = n / 2;

            if (m < Bernoulli.Length)
            {
                return(Bernoulli[m]);
            }

            // Otherwise, use the relationship with the Riemann zeta function to get the Bernoulli number.
            // Since this is only done for large n, it would probably be faster to just sum the zeta series explicitly here.
            double B = 2.0 * AdvancedMath.RiemannZeta(n) / AdvancedMath.PowerOverFactorial(Global.TwoPI, n);

            if (m % 2 == 0)
            {
                B = -B;
            }
            return(B);
        }