예제 #1
0
        public static MultiPrecision <N> EllipticE(MultiPrecision <N> k)
        {
            if (!k.IsFinite || k.Sign == Sign.Minus || k > One)
            {
                return(NaN);
            }

            if (k.IsZero)
            {
                return(PI / 2);
            }

            if (k == One)
            {
                return(One);
            }

            if ((1 - k).Exponent >= -32)
            {
                MultiPrecision <N> y = MultiPrecision <Plus1 <N> > .EllipticECore(
                    k.Convert <Plus1 <N> >(),
                    new Dictionary <MultiPrecision <Plus1 <N> >, MultiPrecision <Plus1 <N> > >()).Convert <N>();

                return(Max(One, y));
            }
            else
            {
                MultiPrecision <N> y = MultiPrecision <Double <N> > .EllipticECore(
                    k.Convert <Double <N> >(),
                    new Dictionary <MultiPrecision <Double <N> >, MultiPrecision <Double <N> > >()).Convert <N>();

                return(Max(One, y));
            }
        }
예제 #2
0
        public static MultiPrecision <N> EllipticK(MultiPrecision <N> k)
        {
            if (!k.IsFinite || k.Sign == Sign.Minus || k > One)
            {
                return(NaN);
            }

            if (k.IsZero)
            {
                return(PI / 2);
            }

            if (k == One)
            {
                return(PositiveInfinity);
            }

            if ((1 - k).Exponent >= -32)
            {
                MultiPrecision <N> y = MultiPrecision <Plus1 <N> > .EllipticKCore(k.Convert <Plus1 <N> >()).Convert <N>();

                return(y);
            }
            else
            {
                MultiPrecision <N> y = MultiPrecision <Double <N> > .EllipticKCore(k.Convert <Double <N> >()).Convert <N>();

                return(y);
            }
        }
예제 #3
0
        private static MultiPrecision <N> BesselKLimit(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            Consts.BesselLimitCoef table = Consts.Bessel.LimitCoef(nu);

            MultiPrecision <Plus4 <N> > z_ex = z.Convert <Plus4 <N> >();
            MultiPrecision <Plus4 <N> > v    = 1 / z_ex;

            MultiPrecision <Plus4 <N> > x = 0, p = 1;

            for (int k = 0; k <= Consts.BesselIK.LimitApproxTerms; k++, p *= v)
            {
                MultiPrecision <Plus4 <N> > c = p * table.Value(k);

                x += c;

                if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                {
                    break;
                }
            }

            MultiPrecision <Plus1 <N> > z_ex1 = z.Convert <Plus1 <N> >();
            MultiPrecision <Plus1 <N> > r     =
                MultiPrecision <Plus1 <N> > .Exp(-z_ex1) * MultiPrecision <Plus1 <N> > .Sqrt(MultiPrecision <Plus1 <N> > .PI / (2 * z_ex1));

            MultiPrecision <Plus1 <N> > y = r * x.Convert <Plus1 <N> >();

            return(y.Convert <N>());
        }
예제 #4
0
        private static MultiPrecision <N> BesselKNearZero(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            int n = (int)Round(nu);

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

                if (dnu.Exponent >= -96)
                {
                    return(MultiPrecision <Plus4 <N> > .BesselKNonIntegerNu(nu.Convert <Plus4 <N> >(), z.Convert <Plus4 <N> >()).Convert <N>());
                }
                if (dnu.Exponent >= -272)
                {
                    return(MultiPrecision <Plus8 <N> > .BesselKNonIntegerNu(nu.Convert <Plus8 <N> >(), z.Convert <Plus8 <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(MultiPrecision <Plus4 <N> > .BesselKIntegerNuNearZero(n, z.Convert <Plus4 <N> >()).Convert <N>());
        }
예제 #5
0
        public static MultiPrecision <N> Gamma(MultiPrecision <N> x)
        {
            if (x.IsNaN || (x.Sign == Sign.Minus && !x.IsFinite))
            {
                return(NaN);
            }

            if (x.IsZero || (x.Sign == Sign.Plus && !x.IsFinite))
            {
                return(PositiveInfinity);
            }

            if (x.Sign == Sign.Minus || x.Exponent < -1)
            {
                MultiPrecision <N> sinpi = SinPI(x);

                if (sinpi.IsZero)
                {
                    return(NaN);
                }

                MultiPrecision <N> y = PI / (sinpi * Gamma(1 - x));

                return(y);
            }
            else
            {
                if (x < Consts.Gamma.Threshold)
                {
                    MultiPrecision <LanczosExpand <N> > a = LanczosAg(x);
                    MultiPrecision <LanczosExpand <N> > s = x.Convert <LanczosExpand <N> >() - MultiPrecision <LanczosExpand <N> > .Point5;
                    MultiPrecision <LanczosExpand <N> > t = (s + Consts.Gamma.Lanczos.G) / MultiPrecision <LanczosExpand <N> > .E;

                    MultiPrecision <LanczosExpand <N> > y_ex = MultiPrecision <LanczosExpand <N> > .Pow(t, s) * a;

                    MultiPrecision <N> y = y_ex.Convert <N>();

                    return(y);
                }
                else
                {
                    MultiPrecision <SterlingExpand <N> > z_ex = x.Convert <SterlingExpand <N> >();

                    MultiPrecision <SterlingExpand <N> > r = MultiPrecision <SterlingExpand <N> > .Sqrt(2 *MultiPrecision <SterlingExpand <N> > .PI / z_ex);

                    MultiPrecision <SterlingExpand <N> > p = MultiPrecision <SterlingExpand <N> > .Pow(z_ex / MultiPrecision <SterlingExpand <N> > .E, z_ex);

                    MultiPrecision <SterlingExpand <N> > s = MultiPrecision <SterlingExpand <N> > .Exp(SterlingTerm(z_ex));

                    MultiPrecision <SterlingExpand <N> > y = r * p * s;

                    return(y.Convert <N>());
                }
            }
        }
예제 #6
0
        private static MultiPrecision <N> BesselJNearZero(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            Consts.BesselNearZeroCoef table = Consts.Bessel.NearZeroCoef(nu);

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

            MultiPrecision <Double <N> > x = 0;
            bool probably_convergenced     = false;

            for (int k = 0; k < int.MaxValue - 1; k += 2, u *= ww)
            {
                MultiPrecision <Double <N> > c = u * (table.Value(k) - w * table.Value(k + 1));

                x += c;

                if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                {
                    if (probably_convergenced)
                    {
                        break;
                    }
                    else
                    {
                        probably_convergenced = true;
                        continue;
                    }
                }
                probably_convergenced = false;

                if (k >= Bits && Math.Max(x.Exponent, c.Exponent) < -Bits * 2)
                {
                    return(0);
                }
            }

            MultiPrecision <Plus1 <N> > p;

            if (nu == Truncate(nu))
            {
                int n = (int)nu;

                p = MultiPrecision <Plus1 <N> > .Pow(z.Convert <Plus1 <N> >() / 2, n);
            }
            else
            {
                p = MultiPrecision <Plus1 <N> > .Pow(z.Convert <Plus1 <N> >() / 2, nu.Convert <Plus1 <N> >());
            }

            MultiPrecision <Plus1 <N> > y = x.Convert <Plus1 <N> >() * p;

            return(y.Convert <N>());
        }
        public static MultiPrecision <N> Erfc(MultiPrecision <N> x)
        {
            if (x.IsZero)
            {
                return(1);
            }
            if (x.IsNaN)
            {
                return(NaN);
            }
            if (!x.IsFinite)
            {
                return(x.Sign == Sign.Plus ? 0 : 2);
            }
            if (x.Sign == Sign.Minus)
            {
                return(1 + Erf(Abs(x)));
            }

            if (x.Exponent < Consts.Erf.ExponentThreshold)
            {
                MultiPrecision <Plus4 <Plus4 <N> > > y =
                    MultiPrecision <Plus4 <N> > .ErfTaylorSeriesApprox(x.Convert <Plus4 <N> >());

                return((1 - y).Convert <N>());
            }
            else
            {
                long n = ErfcConvergenceTable.N(Bits, (double)x);
                MultiPrecision <Plus4 <N> > y = ErfcContinueFractionalApprox(x, n);

                return(y.Convert <N>());
            }
        }
예제 #8
0
        internal static MultiPrecision <N> SquareAsin(MultiPrecision <N> x)
        {
#if DEBUG
            Debug <ArithmeticException> .Assert(x >= Zero && x < One);
#endif

            MultiPrecision <Plus1 <N> > x_expand = x.Convert <Plus1 <N> >();
            MultiPrecision <Plus1 <N> > z = MultiPrecision <Plus1 <N> > .Zero, dz = MultiPrecision <Plus1 <N> > .Zero;
            MultiPrecision <Plus1 <N> > s = 4 * x_expand * x_expand, t = s;

#if DEBUG
            bool convergenced = false;
#endif

            foreach (MultiPrecision <Plus1 <N> > f in Consts.SquareAsin.FracTable)
            {
                dz = t * f;
                z += dz;
                t *= s;

                if (dz.IsZero || z.Exponent - dz.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                {
#if DEBUG
                    convergenced = true;
#endif
                    break;
                }
            }

#if DEBUG
            Debug <ArithmeticException> .Assert(convergenced);
#endif

            return(z.Convert <N>() / 2);
        }
예제 #9
0
        public static MultiPrecision <N> EllipticPi(MultiPrecision <N> n, MultiPrecision <N> k)
        {
            if (!k.IsFinite || k.Sign == Sign.Minus || k > One || n > One)
            {
                return(NaN);
            }

            if (n.IsZero)
            {
                return(EllipticK(k));
            }

            if (n == One)
            {
                return(PositiveInfinity);
            }

            if (k.IsZero)
            {
                return(PI / (2 * Sqrt(1 - n)));
            }

            if (k == One)
            {
                return(PositiveInfinity);
            }

            MultiPrecision <N> y = MultiPrecision <Plus1 <N> > .EllipticPiCore(n.Convert <Plus1 <N> >(), k.Convert <Plus1 <N> >()).Convert <N>();

            return(y);
        }
예제 #10
0
        public static MultiPrecision <N> BesselK(MultiPrecision <N> nu, MultiPrecision <N> x)
        {
            if (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 || x.Sign == Sign.Minus)
            {
                return(NaN);
            }

            if (nu.Sign == Sign.Minus)
            {
                return(BesselK(Abs(nu), x));
            }

            if (nu - Point5 == Floor(nu))
            {
                long n = (long)Floor(nu);

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

                    if (n == 0)
                    {
                        return(r.Convert <N>());
                    }
                    if (n == 1)
                    {
                        return((r * (1 + 1 / x_ex)).Convert <N>());
                    }
                }
            }

            if (x.Exponent <= -0x1000000)
            {
                return(nu.IsZero ? PositiveInfinity : NaN);
            }

            if (x < Consts.BesselIK.ApproxThreshold)
            {
                return(BesselKNearZero(nu, x));
            }
            else
            {
                return(BesselKLimit(nu, x));
            }
        }
예제 #11
0
        private static MultiPrecision <N> BesselILimit(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            Consts.BesselLimitCoef table = Consts.Bessel.LimitCoef(nu);

            MultiPrecision <Plus4 <N> > z_ex = z.Convert <Plus4 <N> >();
            MultiPrecision <Plus4 <N> > v    = 1 / z_ex;

            MultiPrecision <Plus4 <N> > x = 0, p = 1;

            Sign sign = Sign.Plus;

            for (int k = 0; k <= Consts.BesselIK.LimitApproxTerms; k++, p *= v)
            {
                MultiPrecision <Plus4 <N> > c = p * table.Value(k);

                if (sign == Sign.Plus)
                {
                    x   += c;
                    sign = Sign.Minus;
                }
                else
                {
                    x   -= c;
                    sign = Sign.Plus;
                }

                if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                {
                    break;
                }
            }

            MultiPrecision <Plus1 <N> > z_ex1 = z.Convert <Plus1 <N> >();
            MultiPrecision <Plus1 <N> > r     =
                MultiPrecision <Plus1 <N> > .Exp(z_ex1) / MultiPrecision <Plus1 <N> > .Sqrt(2 *MultiPrecision <Plus1 <N> > .PI *z_ex1);

            MultiPrecision <Plus1 <N> > y = r * x.Convert <Plus1 <N> >();

            return(y.Convert <N>());
        }
예제 #12
0
        private static MultiPrecision <N> BesselINearZero(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            Consts.BesselNearZeroCoef table = Consts.Bessel.NearZeroCoef(nu);

            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> > x = 0;

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

                x += c;

                if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                {
                    break;
                }
            }

            MultiPrecision <Plus1 <N> > p;

            if (nu == Truncate(nu))
            {
                int n = (int)nu;

                p = MultiPrecision <Plus1 <N> > .Pow(z.Convert <Plus1 <N> >() / 2, n);
            }
            else
            {
                p = MultiPrecision <Plus1 <N> > .Pow(z.Convert <Plus1 <N> >() / 2, nu.Convert <Plus1 <N> >());
            }

            MultiPrecision <Plus1 <N> > y = x.Convert <Plus1 <N> >() * p;

            return(y.Convert <N>());
        }
예제 #13
0
        private static MultiPrecision <N> BesselYNonIntegerNu(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            Consts.BesselNearZeroCoef table_pos = Consts.Bessel.NearZeroCoef(nu);
            Consts.BesselNearZeroCoef table_neg = Consts.Bessel.NearZeroCoef(-nu);

            MultiPrecision <Double <N> > z_ex = z.Convert <Double <N> >(), nu_ex = nu.Convert <Double <N> >();
            MultiPrecision <Double <N> > p = MultiPrecision <Double <N> > .Pow(z_ex / 2, nu_ex);

            MultiPrecision <Double <N> > cos = MultiPrecision <Double <N> > .Consts.Bessel.SinCos(nu_ex).cos;

            MultiPrecision <Double <N> > u = p * cos, v = 1 / p;
            MultiPrecision <Double <N> > w = z_ex * z_ex, ww = w * w;

            MultiPrecision <Double <N> > x = 0;
            bool probably_convergenced     = false;

            for (int k = 0; k < int.MaxValue - 1; k += 2, u *= ww, v *= ww)
            {
                MultiPrecision <Double <N> > c_pos = u * (table_pos.Value(k) - w * table_pos.Value(k + 1));
                MultiPrecision <Double <N> > c_neg = v * (table_neg.Value(k) - w * table_neg.Value(k + 1));

                MultiPrecision <Double <N> > c = c_pos - c_neg;

                x += c;

                if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                {
                    if (probably_convergenced)
                    {
                        break;
                    }
                    else
                    {
                        probably_convergenced = true;
                        continue;
                    }
                }
                probably_convergenced = false;

                if (k >= Bits && Math.Max(x.Exponent, c.Exponent) < -Bits * 2)
                {
                    return(0);
                }
            }

            MultiPrecision <Plus1 <N> > sin = MultiPrecision <Plus1 <N> > .Consts.Bessel.SinCos(nu.Convert <Plus1 <N> >()).sin;

            MultiPrecision <Plus1 <N> > y = x.Convert <Plus1 <N> >() / sin;

            return(y.Convert <N>());
        }
예제 #14
0
        internal static MultiPrecision <N> CosHalfPI(MultiPrecision <N> x)
        {
            if (!x.IsFinite)
            {
                return(NaN);
            }

            if (x.Exponent < 0)
            {
                return(MultiPrecision <Plus1 <N> > .CosCurveTaylorApprox(x.Convert <Plus1 <N> >()).Convert <N>());
            }

            return(CosCurveTaylorApprox(x));
        }
예제 #15
0
        private static MultiPrecision <N> BesselYLimit(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            Consts.BesselLimitCoef table = Consts.Bessel.LimitCoef(nu);

            MultiPrecision <Plus4 <N> > z_ex = z.Convert <Plus4 <N> >();
            MultiPrecision <Plus4 <N> > v    = 1 / z_ex;
            MultiPrecision <Plus4 <N> > w    = v * v;

            MultiPrecision <Plus4 <N> > x = 0, y = 0, p = 1, q = v;

            Sign sign = Sign.Plus;

            for (int k = 0; k <= Consts.BesselJY.LimitApproxTerms; k++, p *= w, q *= w)
            {
                MultiPrecision <Plus4 <N> > c = p * table.Value(k * 2);
                MultiPrecision <Plus4 <N> > s = q * table.Value(k * 2 + 1);

                if (sign == Sign.Plus)
                {
                    x   += c;
                    y   += s;
                    sign = Sign.Minus;
                }
                else
                {
                    x   -= c;
                    y   -= s;
                    sign = Sign.Plus;
                }

                if (!c.IsZero && x.Exponent - c.Exponent <= MultiPrecision <Plus2 <N> > .Bits)
                {
                    continue;
                }
                if (!s.IsZero && y.Exponent - s.Exponent <= MultiPrecision <Plus2 <N> > .Bits)
                {
                    continue;
                }

                break;
            }

            MultiPrecision <Plus4 <N> > omega = z_ex - (2 * nu.Convert <Plus4 <N> >() + 1) * MultiPrecision <Plus4 <N> > .PI / 4;
            MultiPrecision <Plus4 <N> > m     = x * MultiPrecision <Plus4 <N> > .Sin(omega) + y * MultiPrecision <Plus4 <N> > .Cos(omega);

            MultiPrecision <Plus4 <N> > t = m * MultiPrecision <Plus4 <N> > .Sqrt(2 / (MultiPrecision <Plus4 <N> > .PI *z_ex));

            return(t.Convert <N>());
        }
예제 #16
0
        private static MultiPrecision <LanczosExpand <N> > LanczosAg(MultiPrecision <N> z)
        {
            MultiPrecision <Double <LanczosExpand <N> > > x_ex = Consts.Gamma.Lanczos.Coef[0];
            MultiPrecision <Double <LanczosExpand <N> > > z_ex = (z - 1).Convert <Double <LanczosExpand <N> > >();

            for (int i = 1; i < Consts.Gamma.Lanczos.N; i++)
            {
                MultiPrecision <Double <LanczosExpand <N> > > w = Consts.Gamma.Lanczos.Coef[i];

                x_ex += w / (z_ex + i);
            }

            MultiPrecision <LanczosExpand <N> > x = x_ex.Convert <LanczosExpand <N> >();

            return(x);
        }
예제 #17
0
        public static MultiPrecision <N> Atan(MultiPrecision <N> x)
        {
            if (x.IsNaN)
            {
                return(NaN);
            }

            if (!x.IsFinite)
            {
                return(x.Sign == Sign.Plus ? PI / 2 : -PI / 2);
            }

            MultiPrecision <Plus1 <N> > x_ex = x.Convert <Plus1 <N> >();

            if (x <= One && x >= MinusOne)
            {
                MultiPrecision <Plus1 <N> > z = MultiPrecision <Plus1 <N> > .Abs(x_ex) / MultiPrecision <Plus1 <N> > .Sqrt(x_ex *x_ex + 1);

                MultiPrecision <N> w = MultiPrecision <Plus1 <N> > .Sqrt(MultiPrecision <Plus1 <N> > .SquareAsin(z)).Convert <N>();

                if (w.IsZero)
                {
                    return(x);
                }

                return(new MultiPrecision <N>(x.Sign, w.exponent, w.mantissa));
            }
            else
            {
                MultiPrecision <Plus1 <N> > invx = 1 / x_ex;
                MultiPrecision <Plus1 <N> > z    = MultiPrecision <Plus1 <N> > .Abs(invx) / MultiPrecision <Plus1 <N> > .Sqrt(invx *invx + 1);

                MultiPrecision <N> w = MultiPrecision <Plus1 <N> > .Sqrt(MultiPrecision <Plus1 <N> > .SquareAsin(z)).Convert <N>();

                if (x.Sign == Sign.Plus)
                {
                    return(PI / 2 - w);
                }
                else
                {
                    return(w - PI / 2);
                }
            }
        }
예제 #18
0
        private static MultiPrecision <N> BesselKNonIntegerNu(MultiPrecision <N> nu, MultiPrecision <N> z)
        {
            Consts.BesselNearZeroCoef table_pos = Consts.Bessel.NearZeroCoef(nu);
            Consts.BesselNearZeroCoef table_neg = Consts.Bessel.NearZeroCoef(-nu);

            MultiPrecision <Double <N> > z_ex = z.Convert <Double <N> >();
            MultiPrecision <Double <N> > p    = MultiPrecision <Double <N> > .Pow(z_ex / 2, nu.Convert <Double <N> >());

            MultiPrecision <Double <N> > u = p, v = 1 / p;
            MultiPrecision <Double <N> > w = z_ex * z_ex;

            MultiPrecision <Double <N> > x = 0;
            bool probably_convergenced     = false;

            for (int k = 0; k < int.MaxValue; k++, u *= w, v *= w)
            {
                MultiPrecision <Double <N> > c_pos = u * table_pos.Value(k), c_neg = v * table_neg.Value(k);
                MultiPrecision <Double <N> > c = c_neg - c_pos;

                x += c;

                if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                {
                    if (probably_convergenced)
                    {
                        break;
                    }
                    else
                    {
                        probably_convergenced = true;
                        continue;
                    }
                }
                probably_convergenced = false;
            }

            MultiPrecision <Plus1 <N> > sin = MultiPrecision <Plus1 <N> > .Consts.Bessel.SinCos(nu.Convert <Plus1 <N> >()).sin;

            MultiPrecision <Plus1 <N> > y = (x.Convert <Plus1 <N> >() * MultiPrecision <Plus1 <N> > .PI) / (2 * sin);

            return(y.Convert <N>());
        }
        public static MultiPrecision <N> Erf(MultiPrecision <N> x)
        {
            if (x.IsZero)
            {
                return(0);
            }
            if (x.IsNaN)
            {
                return(NaN);
            }
            if (!x.IsFinite)
            {
                return(x.Sign == Sign.Plus ? 1 : -1);
            }
            if (x.Sign == Sign.Minus)
            {
                return(-Erf(Abs(x)));
            }

            if (x.Exponent < Consts.Erf.ExponentThreshold)
            {
                MultiPrecision <Plus4 <N> > y = ErfTaylorSeriesApprox(x);

                return(y.Convert <N>());
            }
            else
            {
                double xd = (double)x;
                double erfc_exponent_estimate = 1.4 * xd * xd;

                int needs_bits = Bits - (int)Math.Min(Bits, erfc_exponent_estimate);
                if (needs_bits < 1)
                {
                    return(1);
                }

                long n = ErfcConvergenceTable.N(needs_bits, xd);
                MultiPrecision <Plus4 <N> > y = ErfcContinueFractionalApprox(x, n);

                return((1 - y).Convert <N>());
            }
        }
                public static MultiPrecision <N> Value(int n)
                {
                    if (n < 0)
                    {
                        throw new ArgumentOutOfRangeException(nameof(n));
                    }

                    if (n < a_table.Count)
                    {
                        return(a_table[n]);
                    }

                    for (int k = a_table.Count; k <= n; k++)
                    {
                        MultiPrecision <Plus1 <N> > a = a_last + (MultiPrecision <Plus1 <N> > .One / k);
                        a_table.Add(a.Convert <N>());
                        a_last = a;
                    }

                    return(a_table[n]);
                }
        public static MultiPrecision <N> Rcp(MultiPrecision <N> x)
        {
            if (x.IsNaN)
            {
                return(NaN);
            }
            if (!x.IsFinite)
            {
                return(Zero);
            }
            if (x.IsZero)
            {
                return(x.Sign == Sign.Plus ? PositiveInfinity : NegativeInfinity);
            }

            MultiPrecision <Plus1 <N> > x_expand = x.Convert <Plus1 <N> >();

            MultiPrecision <Plus1 <N> > v = new(Sign.Plus, 0, x_expand.mantissa, round : false);

            MultiPrecision <Plus1 <N> > a = 1d / (double)v;
            MultiPrecision <Plus1 <N> > h = 1 - v * a;
            UInt32 h_exponent_prev = ExponentMax, h_exponent_post = h.exponent;

            while (h_exponent_prev > h_exponent_post && !h.IsZero)
            {
                MultiPrecision <Plus1 <N> > squa_h = h * h;

                a *= 1 + (1 + squa_h) * (h + squa_h);
                h  = 1 - v * a;

                h_exponent_prev = h_exponent_post;
                h_exponent_post = h.exponent;
            }

            MultiPrecision <Plus1 <N> > y_expand = new(x.Sign, -x.Exponent + a.Exponent, a.mantissa, round : false);

            MultiPrecision <N> y = y_expand.Convert <N>();

            return(y);
        }
예제 #22
0
        public static MultiPrecision <N> Cbrt(MultiPrecision <N> x)
        {
            if (x.IsNaN)
            {
                return(NaN);
            }
            if (!x.IsFinite)
            {
                return((x.Sign == Sign.Plus) ? PositiveInfinity : NegativeInfinity);
            }
            if (x.IsZero)
            {
                return(Zero);
            }

            MultiPrecision <Plus1 <N> > x_expand = x.Convert <Plus1 <N> >();

            Int64 exponent = x_expand.Exponent;
            MultiPrecision <Plus1 <N> > v = new(Sign.Plus, exponent % 3, x_expand.mantissa, round : false);

            MultiPrecision <Plus1 <N> > a = 1d / Math.Cbrt((double)v);
            MultiPrecision <Plus1 <N> > h = 1 - v * a * a * a;
            UInt32 h_exponent_prev = ExponentMax, h_exponent_post = h.exponent;

            while (h_exponent_prev > h_exponent_post && !h.IsZero)
            {
                a *= 1 + h * (27 + h * (18 + h * 14)) / 81;
                h  = 1 - v * a * a * a;

                h_exponent_prev = h_exponent_post;
                h_exponent_post = h.exponent;
            }

            MultiPrecision <Plus1 <N> > y_expand = MultiPrecision <Plus1 <N> > .Ldexp(v *a *a, (int)((exponent - exponent % 3) / 3));

            MultiPrecision <N> y = y_expand.Convert <N>();

            return((x.Sign == Sign.Plus) ? y : -y);
        }
예제 #23
0
        private static ReadOnlyCollection <MultiPrecision <N> > GenerateTaylorSequence()
        {
            List <MultiPrecision <N> > table = new();

            MultiPrecision <Plus1 <N> > v = 1, d = 1, t = 1;

            while (table.Count < 1024 || t.Exponent >= -Bits * 2)
            {
                t = 1 / v;

                if (t.IsZero)
                {
                    break;
                }

                table.Add(t.Convert <N>());
                d += 1;
                v *= d;
            }

            return(table.AsReadOnly());
        }
예제 #24
0
        public static MultiPrecision <N> Asin(MultiPrecision <N> x)
        {
            if (!(x >= MinusOne && x <= One))
            {
                return(NaN);
            }

            if (x == MinusOne)
            {
                return(-PI / 2);
            }
            if (x == One)
            {
                return(PI / 2);
            }

            if (Abs(x) <= Sqrt2 / 2)
            {
                MultiPrecision <Plus1 <N> > x_ex = x.Convert <Plus1 <N> >();

                MultiPrecision <N> w =
                    MultiPrecision <Plus1 <N> > .Sqrt(
                        MultiPrecision <Plus1 <N> > .SquareAsin(
                            MultiPrecision <Plus1 <N> > .Abs(x_ex))).Convert <N>();

                if (w.IsZero)
                {
                    return(x);
                }

                return(new MultiPrecision <N>(x.Sign, w.exponent, w.mantissa));
            }
            else
            {
                MultiPrecision <N> z = x / (Sqrt(1 - x * x) + 1);
                return(Atan(z) * 2);
            }
        }
        private static MultiPrecision <Plus4 <N> > ErfTaylorSeriesApprox(MultiPrecision <N> z)
        {
            MultiPrecision <Plus4 <N> > z_ex = z.Convert <Plus4 <N> >();
            MultiPrecision <Plus4 <N> > w = z_ex * z_ex, v = w;
            MultiPrecision <Plus4 <N> > y = 1;

            foreach (MultiPrecision <Plus4 <N> > t in Consts.Erf.ErfDenomTable)
            {
                MultiPrecision <Plus4 <N> > dy = t * v;
                y += dy;

                if (dy.IsZero || y.Exponent - dy.Exponent > MultiPrecision <Plus4 <N> > .Bits)
                {
                    break;
                }

                v *= w;
            }

            y *= 2 * z_ex * Consts.Erf.C;

            return(y);
        }
        private static MultiPrecision <Plus4 <N> > ErfcContinueFractionalApprox(MultiPrecision <N> z, long n)
        {
            MultiPrecision <Plus4 <N> > z_ex = z.Convert <Plus4 <N> >();
            MultiPrecision <Plus4 <N> > w    = z_ex * z_ex;

            MultiPrecision <Plus4 <N> > f =
                (MultiPrecision <Plus4 <N> > .Sqrt(25 + w * (440 + w * (488 + w * 16 * (10 + w))))
                 - 5 + w * 4 * (1 + w))
                / (20 + w * 8);

            for (long k = checked (4 * n - 3); k >= 1; k -= 4)
            {
                MultiPrecision <Plus4 <N> > c0 = (k + 2) * f;
                MultiPrecision <Plus4 <N> > c1 = w * ((k + 3) + 2 * f);
                MultiPrecision <Plus4 <N> > d0 = checked ((k + 1) * (k + 3)) + (4 * k + 6) * f;
                MultiPrecision <Plus4 <N> > d1 = 2 * c1;

                f = w + k * (c0 + c1) / (d0 + d1);
            }

            MultiPrecision <Plus4 <N> > y = z_ex * MultiPrecision <Plus4 <N> > .Exp(-w) * Consts.Erf.C / f;

            return(y);
        }
예제 #27
0
        public static MultiPrecision <N> BesselI(MultiPrecision <N> nu, MultiPrecision <N> x)
        {
            if (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 || x.Sign == Sign.Minus)
            {
                return(NaN);
            }

            if (nu.Sign == Sign.Minus && nu == Truncate(nu))
            {
                return(BesselI(Abs(nu), x));
            }

            if (nu - Point5 == Floor(nu))
            {
                long n = (long)Floor(nu);

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

                    if (n == -2)
                    {
                        return(-(r * (MultiPrecision <Plus1 <N> > .Cosh(x_ex) / x_ex - MultiPrecision <Plus1 <N> > .Sinh(x_ex))).Convert <N>());
                    }
                    if (n == -1)
                    {
                        return((r * MultiPrecision <Plus1 <N> > .Cosh(x_ex)).Convert <N>());
                    }
                    if (n == 0)
                    {
                        MultiPrecision <N> y = (r * MultiPrecision <Plus1 <N> > .Sinh(x_ex)).Convert <N>();

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

                        return(y.IsNormal ? y : 0);
                    }
                }
            }

            if (x.Exponent <= -0x1000000)
            {
                return(nu.IsZero ? 1 : ((nu.Sign == Sign.Plus || nu == Truncate(nu)) ? 0 : NaN));
            }

            if (x < Consts.BesselIK.ApproxThreshold)
            {
                return(BesselINearZero(nu, x));
            }
            else
            {
                return(BesselILimit(nu, x));
            }
        }
예제 #28
0
        private static MultiPrecision <N> BesselKIntegerNuNearZero(int n, MultiPrecision <N> z)
        {
            Consts.BesselNearZeroCoef               nearzero_table    = Consts.Bessel.NearZeroCoef(n);
            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> > m = MultiPrecision <Double <N> > .Pow(z_ex / 2, n), inv_mm = 1 / (m * m);

            MultiPrecision <Double <N> > u = m, v = 2 * m * MultiPrecision <Double <N> > .Log(z_ex / 2);

            MultiPrecision <Double <N> > w = z_ex * z_ex;

            MultiPrecision <Double <N> > x = 0;
            bool probably_convergenced     = false;

            Sign sign = Sign.Plus;

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

                if ((n & 1) == 0)
                {
                    x += c;
                }
                else
                {
                    x -= c;
                }

                if (k < n)
                {
                    MultiPrecision <Double <N> > d = u * inv_mm * finite_table.Value(k);

                    if (sign == Sign.Plus)
                    {
                        x   += d;
                        sign = Sign.Minus;
                    }
                    else
                    {
                        x   -= d;
                        sign = Sign.Plus;
                    }
                }
                else
                {
                    if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <Plus1 <N> > .Bits)
                    {
                        if (probably_convergenced)
                        {
                            break;
                        }
                        else
                        {
                            probably_convergenced = true;
                            continue;
                        }
                    }
                    probably_convergenced = false;
                }
            }

            MultiPrecision <N> y = x.Convert <N>() / 2;

            return(y);
        }
예제 #29
0
        public static MultiPrecision <N> BesselY(MultiPrecision <N> nu, MultiPrecision <N> x)
        {
            if (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(NaN);
            }

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

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

            if (!x.IsFinite)
            {
                return(0);
            }
            if (x.Exponent >= Bits)
            {
                return(NaN);
            }

            if (nu.Sign == Sign.Minus && nu == Truncate(nu))
            {
                long n = (long)nu;
                return(((n & 1L) == 0) ? BesselY(Abs(nu), x) : -BesselY(Abs(nu), x));
            }

            if (nu - Point5 == Floor(nu))
            {
                long n = (long)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.IsNaN ? 0 : y);
                    }
                    if (n == -1)
                    {
                        MultiPrecision <N> y = (envelope * MultiPrecision <Plus1 <N> > .Sin(x_ex)).Convert <N>();

                        return(y.IsNaN ? 0 : y);
                    }
                    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 (x.Exponent <= -0x1000000)
            {
                return(nu.IsZero ? NegativeInfinity : NaN);
            }

            if (x < Consts.BesselJY.ApproxThreshold)
            {
                return(BesselYNearZero(nu, x).Convert <N>());
            }
            else
            {
                return(BesselYLimit(nu, x));
            }
        }
예제 #30
0
        public static MultiPrecision <N> LogGamma(MultiPrecision <N> x)
        {
            if (x.IsNaN || x.IsZero || x.Sign == Sign.Minus)
            {
                return(NaN);
            }

            if (!x.IsFinite)
            {
                return(PositiveInfinity);
            }

            if (x.Exponent < -1)
            {
                return(Log(Gamma(x)));
            }

            if ((x - 1).Exponent <= -Bits / 8)
            {
                x -= 1;

                return(x * (-226800 * EulerGamma
                            + x * (18900 * (PI * PI)
                                   + x * (-75600 * Zeta3
                                          + x * (630 * Pow(PI, 4)
                                                 + x * (-45360 * Zeta5
                                                        + x * (40 * Pow(PI, 6)
                                                               + x * (-32400 * Zeta7
                                                                      + x * (3 * Pow(PI, 8))))))))) / 226800);
            }

            if ((x - 2).Exponent <= -Bits / 8)
            {
                x -= 2;

                return(x * (226800 * (1 - EulerGamma)
                            + x * (18900 * ((PI * PI) - 6)
                                   + x * (75600 * (1 - Zeta3)
                                          + x * (630 * (Pow(PI, 4) - 90)
                                                 + x * (45360 * (1 - Zeta5)
                                                        + x * (40 * (Pow(PI, 6) - 945)
                                                               + x * (32400 * (1 - Zeta7)
                                                                      + x * (3 * (Pow(PI, 8) - 9450))))))))) / 226800);
            }

            if (x < Consts.Gamma.Threshold)
            {
                MultiPrecision <LanczosExpand <N> > a = MultiPrecision <LanczosExpand <N> > .Log(LanczosAg(x));

                MultiPrecision <LanczosExpand <N> > s = x.Convert <LanczosExpand <N> >() - MultiPrecision <LanczosExpand <N> > .Point5;
                MultiPrecision <LanczosExpand <N> > t = MultiPrecision <LanczosExpand <N> > .Log(s + Consts.Gamma.Lanczos.G);

                MultiPrecision <LanczosExpand <N> > y_ex = a + s * (t - 1);

                MultiPrecision <N> y = y_ex.Convert <N>();

                return(y);
            }
            else
            {
                MultiPrecision <SterlingExpand <N> > z_ex = x.Convert <SterlingExpand <N> >();

                MultiPrecision <SterlingExpand <N> > p = (z_ex - MultiPrecision <SterlingExpand <N> > .Point5) * MultiPrecision <SterlingExpand <N> > .Log(z_ex);

                MultiPrecision <SterlingExpand <N> > s = SterlingTerm(z_ex);

                MultiPrecision <SterlingExpand <N> > y = Consts.Gamma.Sterling.LogBias - z_ex + p + s;

                return(y.Convert <N>());
            }
        }