我有自己的数值积分(正交)子例程,它是Bulirsch&Stoer于1967年出版的ALGOL程序的C ++改编(Numerische Mathematik,9,271-278)。
我想升级到更现代的(自适应)算法,并想知道是否有(免费)C ++库提供了这种算法。我看起来像GSL(它是C),但是它带有一个可怕的API(尽管数字可能不错)。还有别的事吗?
一个有用的API如下所示:
double quadrature(double lower_integration_limit,
double upper_integration_limit,
std::function<double(double)> const&func,
double desired_error_bound_relative=1.e-12,
double desired_error_bound_absolute=0,
double*error_estimate=nullptr);
7
顺便说一句,您会发现许多计算科学中的最佳实现都具有“不良” API,这仅仅是因为它们已经开发了数十年,而不是其他软件的数月或数年。我认为这是可以接受的,并且对于您编写包装API并在内部调用不太干净的API可能非常有用。这为您在主代码中提供了一个不错的API带来了好处,并且还使您仅需重写一个函数就可以在不同的正交库之间轻松切换。
—
Godric Seer 2015年
@GodricSeer如果就这么简单,我会做到这一点。但是,事实并非如此。GSL API需要一个预分配的缓冲区,该缓冲区可能未使用任何缓冲区,但可能太小(需要另一个具有更多内存的调用)。适当的实现是递归的,不需要分配,将所有数据保留在堆栈中,并提供干净的API。
—
Walter
@GodricSeer GSL API的另一个严重问题是,它仅接受不带状态的函数(因为它使用了简单的函数指针)。因此,为具有状态的函数生成线程安全API效率很低。
—
Walter
我同意Godric Seer的观点,写包装纸是最好的选择。我认为“ GSL只接受没有状态的函数”是不正确的:在文档中,这里说a
—
Kirill 2015年
gsl_function
是一个函数指针以及一些不透明的数据指针,可以包含您的状态。其次,关于(重新)分配任意大的工作缓冲区存在一些效率问题,因此该部分至少有一些合理的理由。
关于GSL的预分配缓冲区的另一条评论。工作区的大小是根据最大间隔数来定义的-因为如果要使正交例程在自适应二等分过多的情况下仍然失败,则只需将工作区的大小设置为二等分数目的上限即可。当您谈论“适当”的实现时,GSL在这里做“正确”的事情,它将当前间隔最大的错误一分为二,这意味着它必须跟踪到目前为止的所有间隔。如果将所有数据保留在堆栈上,则可能会耗尽堆栈内存,这并不是真的更好。
—
Kirill