假设我想编写一个通用的数值积分脚本,该脚本采用用户定义的函数并在变量int x
上积分。进一步假设该函数可以调用任意数量的数据列表。例如假设我希望集成商f_integrator
能够集成以下任何产品:
integrand(x)=f(x)
integrand(x)=f(x)*g(x)
integrand(x)=(f(x)+g(x)/h(x))
integrand(x)=pow(f(x),2)*k(x)
那么看来我们需要它能够调用只是一个定义良好的函数,而无需指定该函数接受多少个参数(也许我们需要指定其中的一部分,例如函数必须具有int x
)。如果是这样,那么我们如何实施呢?如果我们应该用另一种方式来做,怎么办?
答案 0 :(得分:0)
如果您需要传递未知数量的参数,则可以为f_integrator
使用可变参数模板
template<typename F, typename... Args >
double f_integrator(F integrand, std::tuple<Args...> const &bounds){
// integrate
}
允许它在具有任意参数类型的函数上工作(假设整数的类型为double
,如果需要,还可以为返回类型添加另一个模板参数)。模板参数F
充当函数类型的角色。然后,您可以直接在函数上调用f_integrator
,例如像这样的lambda
double integral = f_integrate([](double x){return f(x)*g(x);},
std::make_tuple(1.0,2.0));
请注意,您可以将任何可调用对象传递给f_integrate
,因为该可调用对象会返回您可以集成的内容。
使用std::tuple
允许以某种在函数主体中可以处理的方式传递积分区域的边界。当然,如果考虑非平凡的集成区域,事情会变得更加复杂,但是您仍然可以传递由Args
数组表示的网格,以将集成区域上的信息传递给f_integrator
。 / p>
如何进行积分本身是一个不同的故事,但是在一个参数与另一个参数之间进行迭代积分的效率不是很高,如果要进行高维积分,蒙特卡洛积分可能是个好方法。 >
这是一个非常通用的解决方案,并且给出了一些温和的假设,有很多方便的实现方法(对于可变参数模板而言,编写积分器的主体并不容易)。如果被整数的所有参数都属于同一类型,则可以像普通向量一样传递边界
template<typename F, typename T>
double f_integrate(F integrand, std::vector<T> const &bounds){
// integrate, much more convenient
}
现在,您提供的示例仅需要一个参数,因此,如果您可以集成一维函数,可以稍微简化一下。如果您仅通过单个参数传递函数,则不需要可变参数模板,只需使用
template<typename F, typename T=double>
double f_integrate(F integrand, T const& lower_bound, T const& upper_bound){
// integrate
}
第二个参数甚至可能不是必需的,因为您可能只对实数进行积分(请注意,对整数的积分只是离散的和,因此在这种情况下无需进行数字积分)。