使用 Jm+1=2mj(m) -j(m-1) 公式在 MATLAB 中计算贝塞尔函数

发布于 2024-12-10 11:25:43 字数 361 浏览 0 评论 0原文

我尝试使用该公式实现贝塞尔函数,这是代码:

function result=Bessel(num);


if num==0
    result=bessel(0,1);
elseif num==1
    result=bessel(1,1);
else
    result=2*(num-1)*Bessel(num-1)-Bessel(num-2);
end;

但是如果我使用 MATLAB 的贝塞尔函数将其与此函数进行比较,我会得到太高的不同值。 例如,如果我输入 Bessel(20) 它会给我 3.1689e+005 作为结果,如果我输入 bessel(20,1) 它会给我 3.8735e-025 ,这是一个完全不同的结果。

I tried to implement bessel function using that formula, this is the code:

function result=Bessel(num);


if num==0
    result=bessel(0,1);
elseif num==1
    result=bessel(1,1);
else
    result=2*(num-1)*Bessel(num-1)-Bessel(num-2);
end;

But if I use MATLAB's bessel function to compare it with this one, I get too high different values.
For example if I type Bessel(20) it gives me 3.1689e+005 as result, if instead I type bessel(20,1) it gives me 3.8735e-025 , a totally different result.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

云巢 2024-12-17 11:25:43

recurrence_bessel

这种递归关系在数学上很好,但在使用浮点数的有限精度表示实现算法时在数值上不稳定。

考虑以下比较:

x = 0:20;
y1 = arrayfun(@(n)besselj(n,1), x);   %# builtin function
y2 = arrayfun(@Bessel, x);            %# your function
semilogy(x,y1, x,y2), grid on
legend('besselj','Bessel')
title('J_\nu(z)'), xlabel('\nu'), ylabel('log scale')

comparison_plot

因此,您可以看到计算值在 9 之后如何开始显着不同。

根据 MA​​TLAB:

BESSELJ 使用 DE Amos 的 Fortran 库的 MEX 接口。

并给出以下实施参考:

DE Amos,“复数贝塞尔函数的子程序包
论证和非负序”,桑迪亚国家实验室报告,
SAND85-1018,1985 年 5 月。

DE Amos,“复杂贝塞尔函数的便携式软件包
论证和非负序”,Trans. Math. Software,1986。

recurrence_bessel

such recurrence relations are nice in mathematics but numerically unstable when implementing algorithms using limited precision representations of floating-point numbers.

Consider the following comparison:

x = 0:20;
y1 = arrayfun(@(n)besselj(n,1), x);   %# builtin function
y2 = arrayfun(@Bessel, x);            %# your function
semilogy(x,y1, x,y2), grid on
legend('besselj','Bessel')
title('J_\nu(z)'), xlabel('\nu'), ylabel('log scale')

comparison_plot

So you can see how the computed values start to differ significantly after 9.

According to MATLAB:

BESSELJ uses a MEX interface to a Fortran library by D. E. Amos.

and gives the following as references for their implementation:

D. E. Amos, "A subroutine package for Bessel functions of a complex
argument and nonnegative order", Sandia National Laboratory Report,
SAND85-1018, May, 1985.

D. E. Amos, "A portable package for Bessel functions of a complex
argument and nonnegative order", Trans. Math. Software, 1986.

素食主义者 2024-12-17 11:25:43

您使用的前向递归关系不稳定。要了解原因,请考虑 BesselJ(n,x) 的值变得越来越小,大约减小了 1/2n 倍。您可以通过查看 J 的泰勒级数的第一项来看到这一点。

因此,您所做的就是从一个稍小的数字的倍数中减去一个大的数字,以获得一个更小的数字。从数字上看,这不会很好地发挥作用。

这么看吧。我们知道结果的数量级为10^-25。您从 1 数量级的数字开始。因此,为了从中获得哪怕一位准确的数字,我们必须知道前两个数字,精度至少为 25 位。我们显然不这么认为,而且重复率实际上是有分歧的。

使用相同的递推关系,从高阶到低阶,是稳定的。当您从 J(20,1) 和 J(19,1) 的正确值开始时,您也可以完全准确地计算低至 0 的所有阶数。为什么这有效?因为现在每一步的数字都在变大。您从一个较大数字的精确倍数中减去一个非常小的数字,以获得一个更大的数字。

The forward recurrence relation you are using is not stable. To see why, consider that the values of BesselJ(n,x) become smaller and smaller by about a factor 1/2n. You can see this by looking at the first term of the Taylor series for J.

So, what you're doing is subtracting a large number from a multiple of a somewhat smaller number to get an even smaller number. Numerically, that's not going to work well.

Look at it this way. We know the result is of the order of 10^-25. You start out with numbers that are of the order of 1. So in order to get even one accurate digit out of this, we have to know the first two numbers with at least 25 digits precision. We clearly don't, and the recurrence actually diverges.

Using the same recurrence relation to go backwards, from high orders to low orders, is stable. When you start with correct values for J(20,1) and J(19,1), you can calculate all orders down to 0 with full accuracy as well. Why does this work? Because now the numbers are getting larger in each step. You're subtracting a very small number from an exact multiple of a larger number to get an even larger number.

少女净妖师 2024-12-17 11:25:43

您只需修改下面用于球面贝塞尔函数的代码即可。它经过充分测试,适用于所有参数和顺序范围。抱歉,这是 C# 语言

     public static Complex bessel(int n, Complex z)
    {
        if (n == 0) return sin(z) / z;
        if (n == 1) return sin(z) / (z * z) - cos(z) / z;

        if (n <= System.Math.Abs(z.real))
        {
            Complex h0 = bessel(0, z);
            Complex h1 = bessel(1, z);
            Complex ret = 0;
            for (int i = 2; i <= n; i++)
            {
                ret = (2 * i - 1) / z * h1 - h0;
                h0 = h1;
                h1 = ret;
                if (double.IsInfinity(ret.real) || double.IsInfinity(ret.imag)) return double.PositiveInfinity;
            }
            return ret;
        }
        else
        {
            double u = 2.0 * abs(z.real) / (2 * n + 1);

            double a = 0.1;
            double b = 0.175;
            int v = n - (int)System.Math.Ceiling((System.Math.Log(0.5e-16 * (a + b * u * (2 - System.Math.Pow(u, 2)) / (1 - System.Math.Pow(u, 2))), 2)));

            Complex ret = 0;
            while (v > n - 1)
            {
                ret = z / (2 * v + 1.0 - z * ret);
                v = v - 1;
            }


            Complex jnM1 = ret;
            while (v > 0)
            {
                ret = z / (2 * v + 1.0 - z * ret);
                jnM1 = jnM1 * ret;
                v = v - 1;
            }
            return jnM1 * sin(z) / z;
        }
    }

You can just modify the code below which is for the Spherical bessel function. It is well tested and works for all arguments and order range. I am sorry it is in C#

     public static Complex bessel(int n, Complex z)
    {
        if (n == 0) return sin(z) / z;
        if (n == 1) return sin(z) / (z * z) - cos(z) / z;

        if (n <= System.Math.Abs(z.real))
        {
            Complex h0 = bessel(0, z);
            Complex h1 = bessel(1, z);
            Complex ret = 0;
            for (int i = 2; i <= n; i++)
            {
                ret = (2 * i - 1) / z * h1 - h0;
                h0 = h1;
                h1 = ret;
                if (double.IsInfinity(ret.real) || double.IsInfinity(ret.imag)) return double.PositiveInfinity;
            }
            return ret;
        }
        else
        {
            double u = 2.0 * abs(z.real) / (2 * n + 1);

            double a = 0.1;
            double b = 0.175;
            int v = n - (int)System.Math.Ceiling((System.Math.Log(0.5e-16 * (a + b * u * (2 - System.Math.Pow(u, 2)) / (1 - System.Math.Pow(u, 2))), 2)));

            Complex ret = 0;
            while (v > n - 1)
            {
                ret = z / (2 * v + 1.0 - z * ret);
                v = v - 1;
            }


            Complex jnM1 = ret;
            while (v > 0)
            {
                ret = z / (2 * v + 1.0 - z * ret);
                jnM1 = jnM1 * ret;
                v = v - 1;
            }
            return jnM1 * sin(z) / z;
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文