private static MultiPrecision <N> BesselKIntegerNuNearZero(int n, MultiPrecision <N> z)
        {
            Consts.BesselIntegerFiniteTermCoef      finite_table      = Consts.Bessel.IntegerFiniteTermCoef(n);
            Consts.BesselIntegerConvergenceTermCoef convergence_table = Consts.Bessel.IntegerConvergenceTermCoef(n);

            MultiPrecision <Double <N> > z_ex = z.Convert <Double <N> >();
            MultiPrecision <Double <N> > u    = 1;
            MultiPrecision <Double <N> > w    = z_ex * z_ex;

            MultiPrecision <Double <N> > r
                = MultiPrecisionSandbox <Double <N> > .BesselINearZero(n, z_ex).Convert <Double <N> >() * MultiPrecision <Double <N> > .Log(z_ex / 2);

            long r_exponent = r.Exponent;

            MultiPrecision <Double <N> > m = MultiPrecision <Double <N> > .Pow(z_ex / 2, n);

            MultiPrecision <Double <N> > x = 0, y = 0;

            Sign sign = Sign.Plus;

            for (int k = 0; k < int.MaxValue; k++, u *= w)
            {
                MultiPrecision <Double <N> > c = u * convergence_table.Value(k);

                y += c;

                if (k < n)
                {
                    if (sign == Sign.Plus)
                    {
                        x   += u * finite_table.Value(k);
                        sign = Sign.Minus;
                    }
                    else
                    {
                        x   -= u * finite_table.Value(k);
                        sign = Sign.Plus;
                    }
                    continue;
                }

                if (r.Exponent < -MultiPrecision <N> .Bits * 8 && (c.IsZero || y.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits))
                {
                    break;
                }

                if (c.IsZero || Math.Min(y.Exponent - c.Exponent, r_exponent - c.Exponent - m.Exponent) > MultiPrecision <Double <N> > .Bits)
                {
                    break;
                }
            }

            MultiPrecision <Double <N> > d = (x / m + ((n & 1) == 0 ? 1 : -1) * (y * m - 2 * r)) / 2;

            return(d.Convert <N>());
        }
        private static MultiPrecision <N> BesselKNearZero(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            int n = (int)MultiPrecision <N> .Round(nu);

            if (nu != n)
            {
                MultiPrecision <N> dnu = nu - n;

                if (dnu.Exponent >= -16)
                {
                    return(MultiPrecisionSandbox <Double <Plus2 <N> > > .BesselKNonIntegerNu(nu.Convert <Double <Plus2 <N> > >(), z.Convert <Double <Plus2 <N> > >()).Convert <N>());
                }
                if (dnu.Exponent >= -32)
                {
                    return(MultiPrecisionSandbox <Double <Plus4 <N> > > .BesselKNonIntegerNu(nu.Convert <Double <Plus4 <N> > >(), z.Convert <Double <Plus4 <N> > >()).Convert <N>());
                }
                if (dnu.Exponent >= -48)
                {
                    return(MultiPrecisionSandbox <Double <Plus8 <N> > > .BesselKNonIntegerNu(nu.Convert <Double <Plus8 <N> > >(), z.Convert <Double <Plus8 <N> > >()).Convert <N>());
                }
                if (dnu.Exponent >= -80)
                {
                    return(MultiPrecisionSandbox <Double <Plus16 <N> > > .BesselKNonIntegerNu(nu.Convert <Double <Plus16 <N> > >(), z.Convert <Double <Plus16 <N> > >()).Convert <N>());
                }
                if (dnu.Exponent >= -144)
                {
                    return(MultiPrecisionSandbox <Double <Plus32 <N> > > .BesselKNonIntegerNu(nu.Convert <Double <Plus32 <N> > >(), z.Convert <Double <Plus32 <N> > >()).Convert <N>());
                }
                if (dnu.Exponent >= -272)
                {
                    return(MultiPrecisionSandbox <Double <Plus64 <N> > > .BesselKNonIntegerNu(nu.Convert <Double <Plus64 <N> > >(), z.Convert <Double <Plus64 <N> > >()).Convert <N>());
                }

                throw new ArgumentException(
                          "The calculation of the BesselK function value is invalid because it loses digits" +
                          " when nu is extremely close to an integer. (|nu - round(nu)| < 1.32 x 10^-82 and nu != round(nu))",
                          nameof(nu));
            }

            return(MultiPrecisionSandbox <Plus4 <N> > .BesselKIntegerNuNearZero(n, z.Convert <Plus4 <N> >()).Convert <N>());
        }
Esempio n. 3
0
            static int plot(StreamWriter sw, decimal nu, int min_matchbits, decimal z)
            {
                MultiPrecision <N> t = MultiPrecisionSandbox <N> .BesselJ(nu, z);

                MultiPrecision <Plus1 <N> > s = MultiPrecisionSandbox <Plus1 <N> > .BesselJ(nu, z);

                sw.WriteLine($"  z: {z}");
                sw.WriteLine($"  f : {t}");
                sw.WriteLine($"  {t.ToHexcode()}");
                sw.WriteLine($"  {s.ToHexcode()}");

                MultiPrecision <N> err = MultiPrecision <N> .Abs(t - s.Convert <N>());

                sw.WriteLine($"  err : {err}");

                for (int keepbits = MultiPrecision <N> .Bits; keepbits >= 0; keepbits--)
                {
                    if (keepbits == 0)
                    {
                        min_matchbits = 0;
                    }
                    else if (MultiPrecision <N> .RoundMantissa(t, MultiPrecision <N> .Bits - keepbits) == MultiPrecision <N> .RoundMantissa(s.Convert <N>(), MultiPrecision <N> .Bits - keepbits))
                    {
                        sw.WriteLine($"  matchbits : {keepbits}");

                        if (keepbits < min_matchbits)
                        {
                            min_matchbits = keepbits;
                        }

                        break;
                    }
                }

                return(min_matchbits);
            }
        public static MultiPrecision <N> BesselY(MultiPrecision <N> nu, MultiPrecision <N> x)
        {
            if (MultiPrecision <N> .Abs(nu) > 64)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(nu),
                          "In the calculation of the Bessel function, nu with an absolute value greater than 64 is not supported."
                          );
            }
            if (nu.IsNaN || x.IsNaN)
            {
                return(MultiPrecision <N> .NaN);
            }

            if (x.Sign == Sign.Minus)
            {
                if (nu != MultiPrecision <N> .Truncate(nu))
                {
                    return(MultiPrecision <N> .NaN);
                }

                long n = (long)nu;
                return(((n & 1L) == 0) ? BesselY(nu, MultiPrecision <N> .Abs(x)) : -BesselY(nu, MultiPrecision <N> .Abs(x)));
            }

            if (!x.IsFinite)
            {
                return(0);
            }
            if (x.IsZero)
            {
                return(MultiPrecision <N> .NegativeInfinity);
            }
            if (nu.Sign == Sign.Minus && nu == MultiPrecision <N> .Truncate(nu))
            {
                long n = (long)nu;
                return(((n & 1L) == 0) ? BesselY(MultiPrecision <N> .Abs(nu), x) : -BesselY(MultiPrecision <N> .Abs(nu), x));
            }

            if (nu - MultiPrecision <N> .Point5 == MultiPrecision <N> .Floor(nu))
            {
                long n = (long)MultiPrecision <N> .Floor(nu);

                if (n >= -2 && n < 2)
                {
                    MultiPrecision <Plus1 <N> > x_ex     = x.Convert <Plus1 <N> >();
                    MultiPrecision <Plus1 <N> > envelope = MultiPrecision <Plus1 <N> > .Sqrt(2 / (MultiPrecision <Plus1 <N> > .PI *x_ex));

                    if (n == -2)
                    {
                        MultiPrecision <N> y = -(envelope * (MultiPrecision <Plus1 <N> > .Sin(x_ex) / x_ex - MultiPrecision <Plus1 <N> > .Cos(x_ex))).Convert <N>();

                        return(y.IsNormal ? y : 0);
                    }
                    if (n == -1)
                    {
                        MultiPrecision <N> y = (envelope * MultiPrecision <Plus1 <N> > .Sin(x_ex)).Convert <N>();

                        return(y.IsNormal ? y : 0);
                    }
                    if (n == 0)
                    {
                        return(-(envelope * MultiPrecision <Plus1 <N> > .Cos(x_ex)).Convert <N>());
                    }
                    if (n == 1)
                    {
                        return(-(envelope * (MultiPrecision <Plus1 <N> > .Cos(x_ex) / x_ex + MultiPrecision <Plus1 <N> > .Sin(x_ex))).Convert <N>());
                    }
                }
            }

            if (MultiPrecision <N> .Length <= 4)
            {
                return(MultiPrecisionSandbox <Plus1 <N> > .BesselY(nu.Convert <Plus1 <N> >(), x.Convert <Plus1 <N> >()).Convert <N>());
            }

            if (x < Consts.BesselJY.ApproxThreshold)
            {
                return(BesselYNearZero(nu, x));
            }
            else
            {
                return(BesselYLimit(nu, x).Convert <N>());
            }
        }