public static MultiPrecision <N> Add(MultiPrecision <N> a, long b) { if (b == 0) { return(a); } if (a.IsNaN) { return(NaN); } if (a.IsZero) { return(b); } if (!a.IsFinite) { return(a); } UInt64 b_abs = UIntUtil.Abs(b); if (a.Sign == UIntUtil.Sign(b)) { (Mantissa <N> n, Int64 exponent, bool round) = Add(a.mantissa, b_abs, -a.Exponent); return(new MultiPrecision <N>(a.Sign, exponent + a.Exponent, n, round)); } else { (Mantissa <N> n, Int64 exponent, bool round, Sign sign) = Diff(a.mantissa, b_abs, -a.Exponent); return(new MultiPrecision <N>(sign == Sign.Plus ? a.Sign : UIntUtil.Sign(b), exponent + a.Exponent, n, round)); } }
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> 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)); } }
private static MultiPrecision <N> EllipticPiCore(MultiPrecision <N> n, MultiPrecision <N> k) { MultiPrecision <N> a = 1; MultiPrecision <N> b = Sqrt(1 - k * k); MultiPrecision <N> p = Sqrt(1 - n); MultiPrecision <N> q = 1; MultiPrecision <N> sum_q = 1; while (!q.IsZero && sum_q.Exponent - q.Exponent < Bits) { MultiPrecision <N> ab = a * b, p_squa = p * p; MultiPrecision <N> p_squa_pab = p_squa + ab, p_squa_mab = p_squa - ab; MultiPrecision <N> a_next = (a + b) / 2; MultiPrecision <N> b_next = Sqrt(ab); MultiPrecision <N> p_next = p_squa_pab / (2 * p); MultiPrecision <N> q_next = q / 2 * p_squa_mab / p_squa_pab; a = a_next; b = b_next; p = p_next; q = q_next; sum_q += q; } MultiPrecision <N> y = (2 + sum_q * n / (1 - n)) * EllipticK(k) / 2; return(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 <SterlingExpand <N> > SterlingTerm(MultiPrecision <SterlingExpand <N> > z) { MultiPrecision <SterlingExpand <N> > v = 1 / z; MultiPrecision <SterlingExpand <N> > w = v * v; MultiPrecision <SterlingExpand <N> > x = 0, u = 1; foreach (MultiPrecision <SterlingExpand <N> > s in Consts.Gamma.Sterling.Coef) { MultiPrecision <SterlingExpand <N> > c = u * s; x += c; if (c.IsZero || x.Exponent - c.Exponent > MultiPrecision <SterlingExpand <N> > .Bits) { break; } u *= w; } MultiPrecision <SterlingExpand <N> > y = x * v; return(y); }
public static MultiPrecision <N> Variance <N>(this IEnumerable <MultiPrecision <N> > source) where N : struct, IConstant { MultiPrecision <N> avg_sq = source.Select((v) => v * v).Average(); MultiPrecision <N> sq_avg = MultiPrecision <N> .Square(source.Average()); return(avg_sq - sq_avg); }
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> 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>()); } }
public static MultiPrecision <N> Truncate(MultiPrecision <N> x) { if (!x.IsFinite) { return(NaN); } if (x.Exponent >= Mantissa <N> .Bits) { throw new ArgumentException( "The Truncate function was given an input value with no decimal precision.", nameof(x) ); } if (x.Exponent < 0) { return(Zero); } UInt32[] vs = x.mantissa.Value.ToArray(); UIntUtil.FlushLSB(vs, (int)x.Exponent); MultiPrecision <N> y = new(x.Sign, x.exponent, new Mantissa <N>(vs, enable_clone: false)); return(y); }
static Erf() { if (Length > 260) { throw new ArgumentOutOfRangeException( "In the erf function, the calculation is invalid for precision greater than 260 in length.", nameof(N) ); } C = 1 / MultiPrecision <Plus4 <N> > .Sqrt(MultiPrecision <Plus4 <N> > .PI); List <MultiPrecision <Plus4 <N> > > table = new(); MultiPrecision <Plus4 <N> > coef = 1; int n = 1; while ((n < int.MaxValue) && (2 * n * ExponentThreshold + coef.Exponent >= -MultiPrecision <Plus4 <N> > .Bits)) { coef = 1 / ErfTaylorSeries.Coef <Plus4 <N> >(n); table.Add(coef); n++; } ErfDenomTable = table.AsReadOnly(); #if DEBUG Trace.WriteLine($"Erf<{Length}> initialized."); #endif }
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> Div(MultiPrecision <N> a, MultiPrecision <N> b) { if (a.IsNaN || b.IsNaN) { return(NaN); } if (b.IsZero) { if (a.IsZero) { return(NaN); } return((a.Sign == b.Sign) ? PositiveInfinity : NegativeInfinity); } if (!a.IsFinite) { if (b.IsFinite) { return((a.Sign == b.Sign) ? PositiveInfinity : NegativeInfinity); } return(NaN); } if (!b.IsFinite) { return((a.Sign == b.Sign) ? Zero : MinusZero); } (Mantissa <N> mantissa, Int64 exponent) = Div((a.mantissa, a.Exponent), (b.mantissa, b.Exponent)); return(new MultiPrecision <N>((a.Sign == b.Sign) ? Sign.Plus : Sign.Minus, exponent, mantissa, round: false)); }
static SquareAsin() { MultiPrecision <Plus1 <N> > n = 1, n_frac = 1, n2_frac = 2; List <MultiPrecision <Plus1 <N> > > fracs = new(); while (fracs.Count < 1 || fracs.Last().Exponent >= -MultiPrecision <Plus1 <N> > .Bits * 2) { fracs.Add((n_frac * n_frac) / (n * n * n2_frac)); n += 1; n_frac *= n; n2_frac *= (2 * n - 1) * (2 * n); if (!n2_frac.IsFinite) { break; } } FracTable = Array.AsReadOnly(fracs.ToArray()); #if DEBUG Trace.WriteLine($"SquareAsin<{Length}> initialized."); #endif }
public static MultiPrecision <N> NewtonRaphsonRootFinding <N>(MultiPrecision <N> x0, Func <MultiPrecision <N>, MultiPrecision <N> > f, Func <MultiPrecision <N>, MultiPrecision <N> > df, [AllowNull] MultiPrecision <N> x_min = null, [AllowNull] MultiPrecision <N> x_max = null, int max_iterations = -1, bool break_overshoot = false) where N : struct, IConstant { if ((x_min != null && x0 < x_min) || (x_max != null && x0 > x_max)) { throw new ArgumentOutOfRangeException(nameof(x0)); } if (!x0.IsFinite) { return(x0); } MultiPrecision <N> dx = f(x0) / df(x0); MultiPrecision <N> x = x0 - dx; Sign prev_sign = dx.Sign; int overshoots = 0; int iter = 0; while ((max_iterations < 0 || iter < max_iterations) && !dx.IsZero && dx.IsFinite && x.Exponent - dx.Exponent <= MultiPrecision <N> .Bits) { dx = f(x) / df(x); x -= dx; if ((x_min != null && x < x_min) || (x_max != null && x > x_max)) { return(MultiPrecision <N> .NaN); } iter++; if (break_overshoot) { if (prev_sign != dx.Sign) { overshoots++; if (overshoots >= 2) { break; } } else { overshoots = 0; } prev_sign = dx.Sign; } } return(x); }
public static MultiPrecision <N> Div(MultiPrecision <N> a, long b) { if (a.IsNaN) { return(NaN); } if (a.IsZero) { if (b == 0) { return(NaN); } return((a.Sign == UIntUtil.Sign(b)) ? Zero : MinusZero); } if (!a.IsFinite) { return((a.Sign == UIntUtil.Sign(b)) ? PositiveInfinity : NegativeInfinity); } if (b == 0) { return((a.Sign == Sign.Plus) ? PositiveInfinity : NegativeInfinity); } if (b == 1) { return(a); } if (b == -1) { return(Neg(a)); } UInt64 b_abs = UIntUtil.Abs(b); if (UIntUtil.IsPower2(b_abs)) { MultiPrecision <N> a_power2 = Ldexp(a, -UIntUtil.Power2(b_abs)); return(b >= 0 ? a_power2 : Neg(a_power2)); } int expands = BigUInt <Plus4 <N> > .Length - BigUInt <N> .Length; BigUInt <Plus4 <N> > acc = new(a.mantissa.Value.ToArray(), expands); acc /= b_abs; int lzc = acc.LeadingZeroCount; acc <<= lzc; Int64 exponent = a.Exponent - lzc; Sign sign = (a.Sign == UIntUtil.Sign(b)) ? Sign.Plus : Sign.Minus; bool round = acc[expands - 1] > UIntUtil.UInt32Round; Mantissa <N> mantissa = new(acc.Value.Skip(expands).ToArray(), enable_clone : false); return(new MultiPrecision <N>(sign, exponent, mantissa, round)); }
public static void Write <N>(this BinaryWriter writer, MultiPrecision <N> n) where N : struct, IConstant { writer.Write((byte)n.Sign); writer.Write(checked ((UInt32)(n.Exponent + MultiPrecision <N> .ExponentZero))); for (int i = 0; i < MultiPrecision <N> .Length; i++) { writer.Write((UInt32)n.Mantissa[i]); } }
public static MultiPrecision <N> Pow2(MultiPrecision <N> x) { if (x.IsNaN) { return(NaN); } MultiPrecision <N> x_int = Floor(x); if (x_int.Exponent >= UIntUtil.UInt32Bits) { if (x.Sign == Sign.Plus) { return(PositiveInfinity); } else { return(Zero); } } Int64 exponent = x_int.mantissa.Value.Last() >> (UIntUtil.UInt32Bits - (int)x_int.Exponent - 1); if (x_int.Sign == Sign.Minus) { exponent = -exponent; } MultiPrecision <N> x_frac = x - x_int; MultiPrecision <N> v = Ln2 * x_frac; if (v.IsZero || v.Exponent < int.MinValue) { return(new MultiPrecision <N>(Sign.Plus, exponent, Mantissa <N> .One, round: false)); } Accumulator <N> a = Accumulator <N> .One, m = new(v.mantissa, (int)v.Exponent), w = m; foreach (var t in Accumulator <N> .TaylorTable) { Accumulator <N> d = w * t; if (d.Digits < Length) { break; } a += d; w = Accumulator <N> .RightRoundShift(w *m, Mantissa <N> .Bits - 1); } (Mantissa <N> n, int sft) = a.Mantissa; MultiPrecision <N> y = new(Sign.Plus, exponent - sft + 1, n, round : false); return(y); }
internal static MultiPrecision <N> R(int i) { for (int k = rs.Count + 1; k <= i; k++) { MultiPrecision <N> r = 1 / (MultiPrecision <N> .Ldexp(MultiPrecision <N> .One, checked (k * 2)) - 1); rs.Add(r); } return(rs[i - 1]); }
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>()); } } }
public static MultiPrecision <N> Round(MultiPrecision <N> x) { if (x.Sign == Sign.Minus) { return(Floor(x + Point5)); } else { return(Floor(TruncateMantissa(x, 1) + Point5)); } }
private static MultiPrecision <N> SinCurveTaylorApprox(MultiPrecision <N> x) { MultiPrecision <N> x_abs = Abs(x); MultiPrecision <N> x_int = Round(x_abs), x_frac = x_abs - x_int, xpi = x_frac * PI / 2, squa_xpi = xpi * xpi; Int64 cycle = x_int.Exponent < UIntUtil.UInt32Bits / 2 ? ((Int64)x_int) % 4 : (Int64)(x_int % 4); if ((cycle == 0 || cycle == 2) && x_frac.IsZero) { return(Zero); } Accumulator <N> a = Accumulator <N> .One, m = new(squa_xpi.mantissa, squa_xpi.Exponent), w = m; Sign s = Sign.Minus; for (int i = (cycle == 0 || cycle == 2) ? 2 : 1; i + 1 < Accumulator <N> .TaylorTable.Count; i += 2) { Accumulator <N> t = Accumulator <N> .TaylorTable[i]; Accumulator <N> d = w * t; if (s == Sign.Plus) { a += d; s = Sign.Minus; } else { a -= d; s = Sign.Plus; } if (d.Digits < Length) { break; } w = Accumulator <N> .MulShift(w, m); } (Mantissa <N> n, int sft) = a.Mantissa; MultiPrecision <N> y; if (cycle == 0 || cycle == 2) { y = new MultiPrecision <N>((cycle == 0 ^ x.Sign == Sign.Plus) ? Sign.Minus : Sign.Plus, -sft + 1, n, round: false); y *= xpi; } else { y = new MultiPrecision <N>((cycle == 1 ^ x.Sign == Sign.Plus) ? Sign.Minus : Sign.Plus, -sft + 1, n, round: false); } return(y); }
public static MultiPrecision <N> Min <N>(this IEnumerable <MultiPrecision <N> > source) where N : struct, IConstant { MultiPrecision <N> min = MultiPrecision <N> .NaN; foreach (var v in source) { min = !(min <= v) ? v : min; } return(min); }
public static MultiPrecision <N> Max <N>(this IEnumerable <MultiPrecision <N> > source) where N : struct, IConstant { MultiPrecision <N> max = MultiPrecision <N> .NaN; foreach (var v in source) { max = !(max >= v) ? v : max; } return(max); }
public static MultiPrecision <N> ETable(int n) { for (int i = e_table.Count; i <= n; i++) { MultiPrecision <N> e = KTable(i) *checked (1 - 2 * i); e_table.Add(e); } return(e_table[n]); }
public static MultiPrecision <N> KTable(int n) { for (int i = k_table.Count; i <= n; i++) { MultiPrecision <N> k = k_table.Last() *checked (4 * i * (i - 1) + 1) / checked (4 * i * i); k_table.Add(k); } return(k_table[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> Ceiling(MultiPrecision <N> x) { MultiPrecision <N> x_int = Truncate(x); MultiPrecision <N> x_frac = x - x_int; if (x_frac > Zero) { x_int += 1; } return(x_int); }
public static MultiPrecision <N> Floor(MultiPrecision <N> x) { MultiPrecision <N> x_int = Truncate(x); MultiPrecision <N> x_frac = x - x_int; if (x_frac < Zero) { x_int -= 1; } return(x_int); }