贝塞尔函数在C++/Fortran

贝塞尔函数在C++/Fortran,c,fortran,fortran90,C,Fortran,Fortran90,如何在Fortran或/和C中从“0”到“无穷大”对包含贝塞尔函数的方程进行数值积分? 我在matlab中做过,但对于较大的输入,这不是真的,在特定的值之后,贝塞尔函数给出了完全错误的结果(matlab中有一个限制)你可以在谷歌上找到很多已经用C实现的贝塞尔函数 最后,它们使用内置类型,并且将被限制在它们可以表示的范围内(就像MATLAB一样)。最好使用双精度浮点表示法,精度为15位。因此,对于较大的数字,它们似乎是四舍五入的。例如:1237846412345000000000.00000

如何在Fortran或/和C中从“0”到“无穷大”对包含贝塞尔函数的方程进行数值积分?
我在matlab中做过,但对于较大的输入,这不是真的,在特定的值之后,贝塞尔函数给出了完全错误的结果(matlab中有一个限制)

你可以在谷歌上找到很多已经用C实现的贝塞尔函数

最后,它们使用内置类型,并且将被限制在它们可以表示的范围内(就像MATLAB一样)。最好使用双精度浮点表示法,精度为15位。因此,对于较大的数字,它们似乎是四舍五入的。例如:1237846412345000000000.00000

当然,关于堆栈溢出的其他人也对此进行了研究


贝塞尔函数的各种积分有大量的分析结果(参见),包括精确在此范围内的定积分。如果你努力用精确的结果将你的表达式改写成可积的表达式,你的境况会好得多,而且几乎肯定会更快更准确。

上次我不得不处理这些事情时,对过零点定义的区间进行简单的积分是最先进的。这在大多数情况下是相对稳定的,如果被积函数接近于零,那么很容易做到

作为游戏的起点,我加入了一些代码。当然,您需要进行收敛检测和错误检查。这不是生产代码,但我想它可能为您提供了一个起点。它使用gsl

在我的iMac上,此代码每次迭代大约需要2µs。包含硬编码的间隔表不会加快速度

我希望这对你有用

#include <iostream>
#include <vector>
#include <gsl/gsl_sf_bessel.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_sf.h>


double f (double x, void * params) {
    double y = 1.0 / (1.0 + x) * gsl_sf_bessel_J0 (x);
    return y;
}

int main(int argc, const char * argv[]) {

    double sum = 0;
    double delta = 0.00001;
    int max_steps = 1000;
    gsl_integration_workspace * w = gsl_integration_workspace_alloc (max_steps);

    gsl_function F;
    F.function = &f;
    F.params = 0;

    double result, error;
    double a,b;
    for(int n=0; n < max_steps; n++)
    {
        if(n==0)
        {
            a = 0.0;
            b = gsl_sf_bessel_zero_J0(1);
        }
        else
        {
            a = n;
            b = gsl_sf_bessel_zero_J0(n+1);
        }
        gsl_integration_qag (&F,  // function
                              besselj0_intervals[n],   // from
                              besselj0_intervals[n+1],   // to
                              0,   // eps absolute
                              1e-4,// eps relative
                              max_steps,
                              GSL_INTEG_GAUSS15,
                              w,
                              &result,
                              &error);
        sum += result;

        std::cout << n << " " << result << " " << sum << "\n";

        if(abs(result) < delta)
            break;
    }
    return 0;
}
#包括
#包括
#包括
#包括
#包括
双f(双x,空*参数){
双y=1.0/(1.0+x)*gsl\u sf\u bessel\u J0(x);
返回y;
}
int main(int argc,const char*argv[]{
双和=0;
双增量=0.00001;
int max_步数=1000;
gsl_集成_工作空间*w=gsl_集成_工作空间_分配(最大步数);
gsl_函数F;
函数=&F;
F.params=0;
双重结果,错误;
双a,b;
对于(int n=0;n<最大步数;n++)
{
如果(n==0)
{
a=0.0;
b=gsl\u sf\u bessel\u zero\u J0(1);
}
其他的
{
a=n;
b=gsl\u sf\u bessel\u zero\u J0(n+1);
}
gsl_集成_qag(&F,//函数
besselj0_区间[n],//从
贝塞尔J0_区间[n+1],//至
0,//eps绝对值
1e-4,//eps相对
最大步数,
GSL_积分高斯15,
W
&结果,,
&误差);
总和+=结果;

是的,我在matlab中试过,但在matlab中我无法得到准确的结果,我有一个方程,但网站不允许我上传它的图像。问题是关于积分还是关于贝塞尔函数?你确定积分没有解析解,是吗?@DrSvanHay没有解析解n据我所知,所以问题是关于积分的。当然,如果你们中有人知道解析解,那就是awesome@johnhenry那么如果F(x)呢?@DrSvanHay我没有明确地写出F(x)的形式因为在这里解释它的起源很复杂,这与我遇到的具体问题有很大关系。我能说的是F(x)它本身不是振荡的,它是一个相当温和的函数,不需要外部库。它们是标准C和标准Fortran的一部分。请求很模糊,但谈到确切的结果是错误的。我想他可能在寻求实现/使用任意精度的数字(如)并利用它们在一个朴素的贝塞尔函数中实现“精确”结果和需要一些内置函数的源。在matlab中输入特定的较大值后,贝塞尔函数无法收敛到常量值,并且在该特定值后,结果将完全错误。贝塞尔函数不会收敛到常量值。如果您知道如何编写自己的函数,请这样做。不要使用external libs,你不知道收敛性或数值稳定性。抓住Ab&Stegun开始破解。