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