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>());
            }
        }
示例#4
0
        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");
            }
        }
示例#8
0
        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})");
            }
        }
示例#9
0
            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>());
            }
        }