在 C++/Fortran 中集成贝塞尔函数
Integration of Bessel functions in C++/Fortran
如何在 Fortran or/and C 中对包含从“0”到 "infinity" 的贝塞尔函数的方程进行积分?
我在 matlab 中做过,但对于较大的输入和特定值后,贝塞尔函数给出了完全错误的结果(Matlab 中有限制)
您几乎可以 google 找到许多已经用 C 语言实现的 Bessel 函数。
http://www.atnf.csiro.au/computing/software/gipsy/sub/bessel.c
http://jean-pierre.moreau.pagesperso-orange.fr/c_bessel.html
https://msdn.microsoft.com/en-us/library/h7zkk1bz.aspx
最后,这些使用内置类型并将限制在它们可以表示的范围内(就像 MATLAB 一样)。充其量,使用双精度浮点表示法期望 15 位精度。因此,对于大数字,它们看起来是四舍五入的。例如。 1237846464123450000000000.00000
当然,Stack Overflow 上的其他人也对此进行了调查。
C++ Bessel function for complex numbers
贝塞尔函数的各种积分有大量解析结果(参见DLMF, Sect. 10.22),包括恰好在此范围内的定积分。你会过得更好,而且几乎肯定会更快更准确,努力将你的表达式重铸成可积分的东西并使用精确的结果。
上次我不得不处理此类事情时,最先进的技术是对零交叉点定义的区间进行简单积分。在大多数情况下,这是相对 stable 并且如果被积函数接近零,那么很容易做到。
作为尝试的起点,我添加了一些代码。当然,您需要进行收敛检测和错误检查。这不是生产代码,但我认为它可能为您提供了一个起点。它使用 gsl。
在我的 iMac 上,这段代码每次迭代大约需要 2 微秒。通过为间隔包含硬编码 table,它不会变得更快。
希望对您有所帮助。
#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;
}
如何在 Fortran or/and C 中对包含从“0”到 "infinity" 的贝塞尔函数的方程进行积分? 我在 matlab 中做过,但对于较大的输入和特定值后,贝塞尔函数给出了完全错误的结果(Matlab 中有限制)
您几乎可以 google 找到许多已经用 C 语言实现的 Bessel 函数。
http://www.atnf.csiro.au/computing/software/gipsy/sub/bessel.c
http://jean-pierre.moreau.pagesperso-orange.fr/c_bessel.html
https://msdn.microsoft.com/en-us/library/h7zkk1bz.aspx
最后,这些使用内置类型并将限制在它们可以表示的范围内(就像 MATLAB 一样)。充其量,使用双精度浮点表示法期望 15 位精度。因此,对于大数字,它们看起来是四舍五入的。例如。 1237846464123450000000000.00000
当然,Stack Overflow 上的其他人也对此进行了调查。
C++ Bessel function for complex numbers
贝塞尔函数的各种积分有大量解析结果(参见DLMF, Sect. 10.22),包括恰好在此范围内的定积分。你会过得更好,而且几乎肯定会更快更准确,努力将你的表达式重铸成可积分的东西并使用精确的结果。
上次我不得不处理此类事情时,最先进的技术是对零交叉点定义的区间进行简单积分。在大多数情况下,这是相对 stable 并且如果被积函数接近零,那么很容易做到。
作为尝试的起点,我添加了一些代码。当然,您需要进行收敛检测和错误检查。这不是生产代码,但我认为它可能为您提供了一个起点。它使用 gsl。
在我的 iMac 上,这段代码每次迭代大约需要 2 微秒。通过为间隔包含硬编码 table,它不会变得更快。
希望对您有所帮助。
#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;
}