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)); } }
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); } }
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>()); }
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>()); }
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>()); } } }
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>()); } }
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); }
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); }
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)); } }
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>()); }
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>()); }
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>()); }
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)); }
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>()); }
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); }
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); } } }
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); }
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); }
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()); }
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); }
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)); } }
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); }
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)); } }
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>()); } }