我有以下函数:
double
neville (double xx, size_t n, const double *x, const double *y, double *work);
此函数在 x
和 y
中存储的 n
个点上,以 xx
进行拉格朗日插值。 work
数组的大小为 2 * n
。由于这是多项式插值,所以 n
大概在 ~5 左右,很少会超过 10。
此函数经过了积极优化,应在紧密循环中调用。分析表明,在循环中堆分配工作数组是不好的。不幸的是,我必须将其打包成类似函数的类,并且客户端必须不知道工作数组。
目前,我使用模板整数参数来表示该函数的次数,并使用 std::array
来避免动态分配 work
数组:
template <size_t n>
struct interpolator
{
double operator() (double xx) const
{
std::array<double, 2 * n> work;
size_t i = locate (xx); // not shown here, no performance impact
// due to clever tricks + nice calling patterns
return neville (xx, n, x + i, y + i, work.data ());
}
const double *x, *y;
};
可以将工作数组作为类的可变成员进行存储,但是operator()
应该被多个线程并发使用。只要在编译时知道n
,这个版本就可以使用。
现在,我需要在运行时指定n
参数。我在思考像这样的解决方案:
double operator() (double xx) const
{
auto work = static_cast<double*> (alloca (n * sizeof (double)));
...
使用 alloca
时会有一些警告:当然,我必须对 n
设定上限以避免 alloca
调用溢出(不管怎么说,使用100次多项式插值是相当愚蠢的)。
但是,我对这种方法感到非常不舒服:
- 我是否忽略了一些明显的
alloca
危险? - 有没有更好的方式来避免堆分配?
double neville (double xx, size_t n, const double *x, const double *y, double *work);
- 你需要运算符重载来编写这个函数吗?哇,我从来不知道! - user529758alloca()
在失败时可能会调用UB,VLAs在C99标准中,alloca()
甚至不是POSIX等。 - user529758alloca
具有完全相同的缺点,除了缺乏标准化。但是 GCC 确实 支持它,如果您想编写可移植代码,可以自己提供alloca.h
(尽管缺乏标准化是一个好观点,并值得修改我的答案)。 - Konrad Rudolph