public static MultiPrecision <N> BesselI(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 || x.Sign == Sign.Minus) { return(MultiPrecision <N> .NaN); } if (nu.Sign == Sign.Minus && nu == MultiPrecision <N> .Truncate(nu)) { return(BesselI(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> > 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 < Consts.BesselIK.ApproxThreshold) { return(BesselINearZero(nu, x).Convert <N>()); } else { return(BesselILimit(nu, x).Convert <N>()); } }
public void AbsTest() { foreach (MultiPrecision <Pow2.N8> x in TestTool.AllRangeSet <Pow2.N8>()) { MultiPrecision <Pow2.N8> y = MultiPrecision <Pow2.N8> .Abs(x); Console.WriteLine(x); Console.WriteLine(y); TestTool.Tolerance(Math.Abs((double)x), y); } }
public static MultiPrecision <N> BesselK(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 || x.Sign == Sign.Minus) { return(MultiPrecision <N> .NaN); } if (x.IsZero) { return(MultiPrecision <N> .PositiveInfinity); } if (nu.Sign == Sign.Minus) { return(BesselK(MultiPrecision <N> .Abs(nu), x)); } if (nu - MultiPrecision <N> .Point5 == MultiPrecision <N> .Floor(nu)) { long n = (long)MultiPrecision <N> .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 < Consts.BesselIK.ApproxThreshold) { return(BesselKNearZero(nu, x)); } else { return(BesselKLimit(nu, x).Convert <N>()); } }
private static void BesselNearZeroConvergenceSummary <N, M>(string filepath, int z_init, int terms) where N : struct, IConstant where M : struct, IConstant { using (StreamWriter sw = new StreamWriter(filepath)) { sw.WriteLine($"bits: {MultiPrecision<N>.Bits}"); int min_matchbits = MultiPrecision <N> .Bits; for (decimal nu = 0; nu <= 2; nu += 1 / 16m) { sw.WriteLine($"nu: {nu}"); for (decimal z = z_init - 4; z <= z_init + 4; z += 1 / 32m) { MultiPrecision <N> t = BesselLimitApprox <N> .Value(nu, z, terms); MultiPrecision <N> s = BesselNearZeroApprox <N, M> .Value(nu, z); sw.WriteLine($" z: {z}"); sw.WriteLine($" LM : {t}"); sw.WriteLine($" NZ : {s}"); sw.WriteLine($" LM : {t.ToHexcode()}"); sw.WriteLine($" NZ : {s.ToHexcode()}"); MultiPrecision <N> err = MultiPrecision <N> .Abs(t - s); 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, MultiPrecision <N> .Bits - keepbits)) { sw.WriteLine($" matchbits : {keepbits}"); if (keepbits < min_matchbits) { min_matchbits = keepbits; } break; } } } } sw.WriteLine($"min matchbits : {min_matchbits}"); } }
public void AbsUnnormalValueTest() { MultiPrecision <Pow2.N8> y = MultiPrecision <Pow2.N8> .Abs(MultiPrecision <Pow2.N8> .NaN); Assert.IsTrue(y.IsNaN); MultiPrecision <Pow2.N8> inf = MultiPrecision <Pow2.N8> .Abs(MultiPrecision <Pow2.N8> .PositiveInfinity); Assert.AreEqual(MultiPrecision <Pow2.N8> .PositiveInfinity, inf); MultiPrecision <Pow2.N8> minf = MultiPrecision <Pow2.N8> .Abs(MultiPrecision <Pow2.N8> .NegativeInfinity); Assert.AreEqual(MultiPrecision <Pow2.N8> .PositiveInfinity, minf); }
public void AbsBorderTest() { foreach (MultiPrecision <Pow2.N8> x in TestTool.EnumerateNeighbor <Pow2.N8>(0)) { MultiPrecision <Pow2.N8> y = MultiPrecision <Pow2.N8> .Abs(x); Console.WriteLine(x); Console.WriteLine(x.ToHexcode()); Console.WriteLine(y); Console.WriteLine(y.ToHexcode()); Console.Write("\n"); TestTool.Tolerance(Math.Abs((double)x), y); } }
public void SinHalfPILargeValueTest() { MultiPrecision <Pow2.N8> half = MultiPrecision <Pow2.N8> .Point5; MultiPrecision <Pow2.N8>[] borders = new MultiPrecision <Pow2.N8>[] { -65538, -65537 - half, -65537, -65536 - half, -65536, -65535 - half, 65535 + half, 65536, 65536 + half, 65537, 65537 + half, 65538 }; foreach (MultiPrecision <Pow2.N8> b in borders) { List <MultiPrecision <Pow2.N8> > ys = new(); foreach (MultiPrecision <Pow2.N8> x in TestTool.EnumerateNeighbor(b)) { MultiPrecision <Pow2.N8> y = MultiPrecision <Pow2.N8> .SinHalfPI(x); Console.WriteLine(x); Console.WriteLine(x.ToHexcode()); Console.WriteLine(y); Console.WriteLine(y.ToHexcode()); Console.Write("\n"); TestTool.Tolerance(Math.Sin((double)x * Math.PI / 2), y, ignore_sign: true); ys.Add(y); } if (b % 2 == 0) { TestTool.SmoothnessSatisfied(ys, 0.5); TestTool.MonotonicitySatisfied(ys); } else if (MultiPrecision <Pow2.N8> .Abs(b % 2) == 1) { TestTool.NearlyNeighbors(ys, 19); TestTool.SmoothnessSatisfied(ys, 0.5); } else { TestTool.NearlyNeighbors(ys, 20); TestTool.SmoothnessSatisfied(ys, 0.5); TestTool.MonotonicitySatisfied(ys); } Console.Write("\n"); } }
public static void SmoothnessSatisfied <N>(IEnumerable <MultiPrecision <N> > vs, double safe_error) where N : struct, IConstant { if (vs.Count() < 3) { throw new InvalidOperationException("Sequence contains less 3 elements"); } MultiPrecision <N>[] us = vs.ToArray(); MultiPrecision <N>[] diff = new MultiPrecision <N> [us.Length - 1]; for (int i = 1; i < us.Length; i++) { MultiPrecision <N> a = us[i - 1], b = us[i]; diff[i - 1] = a - b; } diff = diff.Where((d) => d.IsFinite).ToArray(); MultiPrecision <N> diff_avg = diff.Average(); MultiPrecision <N> diff_absave = diff.Select((d) => MultiPrecision <N> .Abs(d)).Average(); MultiPrecision <N> diff_nonzeromin = diff.Where((d) => !d.IsZero).Select((d) => MultiPrecision <N> .Abs(d)).Min(); MultiPrecision <N> error_range = diff_absave * safe_error + diff_nonzeromin; if (diff_absave.IsZero || error_range.IsZero) { Console.WriteLine("Smoothness satisfied. (No error)"); return; } MultiPrecision <N> max_error_rate = diff.Select((d) => MultiPrecision <N> .Abs(d - diff_avg) / error_range).Max(); if (max_error_rate < safe_error) { Console.WriteLine($"Smoothness satisfied. (Max Error Rate:{max_error_rate:E4})"); return; } else { Assert.Fail($"Smoothness not satisfied. (Max Error Rate:{max_error_rate:E4})"); } }
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 void SinHalfPIBorderTest() { MultiPrecision <Pow2.N8> half_n8 = MultiPrecision <Pow2.N8> .Point5; MultiPrecision <Pow2.N8>[] borders_n8 = new MultiPrecision <Pow2.N8>[] { -4 - half_n8, -4, -3 - half_n8, -3, -2 - half_n8, -2, -1 - half_n8, -1, -0 - half_n8, 0, 0 + half_n8, 1, 1 + half_n8, 2, 2 + half_n8, 3, 3 + half_n8, 4, 4 + half_n8 }; foreach (MultiPrecision <Pow2.N8> b in borders_n8) { List <MultiPrecision <Pow2.N8> > ys = new(); foreach (MultiPrecision <Pow2.N8> x in TestTool.EnumerateNeighbor(b)) { MultiPrecision <Pow2.N8> y = MultiPrecision <Pow2.N8> .SinHalfPI(x); Console.WriteLine(x); Console.WriteLine(x.ToHexcode()); Console.WriteLine(y); Console.WriteLine(y.ToHexcode()); Console.Write("\n"); TestTool.Tolerance(Math.Sin((double)x * Math.PI / 2), y, ignore_sign: true); ys.Add(y); } if (b % 2 == 0) { TestTool.SmoothnessSatisfied(ys, 0.5); TestTool.MonotonicitySatisfied(ys); } else if (MultiPrecision <Pow2.N8> .Abs(b % 2) == 1) { TestTool.NearlyNeighbors(ys, 3); TestTool.SmoothnessSatisfied(ys, 1); } else { TestTool.NearlyNeighbors(ys, 4); TestTool.SmoothnessSatisfied(ys, 1); TestTool.MonotonicitySatisfied(ys); } Console.Write("\n"); } MultiPrecision <Pow2.N16> half_n16 = MultiPrecision <Pow2.N16> .Point5; MultiPrecision <Pow2.N16>[] borders_n16 = new MultiPrecision <Pow2.N16>[] { -4 - half_n16, -4, -3 - half_n16, -3, -2 - half_n16, -2, -1 - half_n16, -1, -0 - half_n16, 0, 0 + half_n16, 1, 1 + half_n16, 2, 2 + half_n16, 3, 3 + half_n16, 4, 4 + half_n16 }; foreach (MultiPrecision <Pow2.N16> b in borders_n16) { List <MultiPrecision <Pow2.N16> > ys = new(); foreach (MultiPrecision <Pow2.N16> x in TestTool.EnumerateNeighbor(b)) { MultiPrecision <Pow2.N16> y = MultiPrecision <Pow2.N16> .SinHalfPI(x); Console.WriteLine(x); Console.WriteLine(x.ToHexcode()); Console.WriteLine(y); Console.WriteLine(y.ToHexcode()); Console.Write("\n"); TestTool.Tolerance(Math.Sin((double)x * Math.PI / 2), y, ignore_sign: true); ys.Add(y); } if (b % 2 == 0) { TestTool.SmoothnessSatisfied(ys, 0.5); TestTool.MonotonicitySatisfied(ys); } else if (MultiPrecision <Pow2.N16> .Abs(b % 2) == 1) { TestTool.NearlyNeighbors(ys, 3); TestTool.SmoothnessSatisfied(ys, 1); } else { TestTool.NearlyNeighbors(ys, 4); TestTool.SmoothnessSatisfied(ys, 1); TestTool.MonotonicitySatisfied(ys); } Console.Write("\n"); } }
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>()); } }