我正在解决一个耦合常微分方程的系统,我希望在程序运行之间更改要集成的函数。到目前为止,我只需要注释和取消注释三个return语句即可在不同的功能之间进行切换,如下所示:
arma::vec acceleration(arma::vec u, double t)
{ /*
The current acceleration of the system.
*/
// return acceleration_1(u);
// return acceleration_2(u);
return acceleration_3(u);
}
acceleration
被调用了很多次,我想使代码高效,但是我也想更改要与输入参数集成的函数,而不是通过输入代码的深度来进行注释和取消-评论不同的陈述。
[如果我要发送一个参数,比如说choice
,它只能是{1, 2, 3}
之一,并且choice
在程序运行期间永不改变,if语句是否会使我的程序变慢?示例:
arma::vec acceleration(arma::vec u, double t, int choice)
{ /*
The current acceleration of the system.
*/
if (choice == 1)
{
return acceleration_1(u);
}
else if (choice == 2)
{
return acceleration_2(u);
}
else if (choice == 3)
{
return acceleration_3(u);
}
}
switch
语句是否更适合(更快)用于此目的?是否有其他选择不会降低代码速度?
编辑:acceleration
和acceleration_x
是成员函数,这些成员函数使使用函数指针的替代解决方案变得困难。
答案取决于情况。
您的程序已编译并在CPU上运行。您没有提及您的项目针对的是哪种CPU体系结构,但是大多数现代CPU使用分支预测,当条件在运行时可能发生变化时,这有助于加快朴素条件检查的速度。
即使就您而言,如您所说,选择变量在程序生命周期中也不会改变,如果没有分支预测,编译器和CPU也就没有太多机会避免每次在您指示时进行检查源代码。它是一个运行时变量,对于C ++,没有适当的结构可帮助编译器或CPU知道何时更改。他们可能会使用巧妙的启发式方法,例如用调用分派(函数调用)替换许多if
语句,但是如果您执行以下操作,那将是相同的:
arma::vec (*chosen_acceleration_proc)(arma::vec, double);
arma::vec acceleration(arma::vec u, double t)
{
return chosen_acceleration_proc(u);
}
您可以在运行时切换所选过程的位置:
chosen_acceleration_proc = acceleration_1; /// For example
如果编译器没有使用inline您不同的加速过程,那么acceleration
过程的唯一额外费用就是调用chosen_acceleration_proc
。现在,实际选择的加速过程的成本可能远远超过调用它的成本。同样,内联将没有太大好处,只要编译器可以自行决定内联而不是您自己决定(C和C ++中的inline
关键字不会强制编译器内联过程)。
您必须分析已编译的程序,以查看此类分发的成本是可忽略的还是巨大的。
返回分支预测,对于具有分支预测的CPU,在进行相同选择一定次数后,CPU将“学习”:
arma::vec acceleration(arma::vec u, double t) {
switch(acceleration_proc_id) {
case 1: return acceleration_1(u, t);
case 2: return acceleration_2(u, t);
/// etc
}
}
......的意思是,当您将acceleration_proc_id
设置为某个选定值时,一段时间后,CPU只会假设它将保持该状态,并预取并推测执行指令,就好像该选择是给定的一样。有关分支预测及其帮助或失败的更多信息,请参见this most excellent answer。
总而言之,CPU可以运行的最佳代码根本就是没有代码-如果您需要在运行时进行切换或调用实际的,非内联的过程,那么成本就在上面,而不是使用预处理器或常数表达式,以确定在编译程序时要使用哪个加速功能。
您最终需要分析使用switch
的程序(它可能比过程指针更快,因为C ++需要switch
中的常量值-编译器可能会生成CPU优化的代码)与使用过程指针。概要分析将确定CPU大部分时间都花在哪里。如果经过分析后得出结论,与实际计算加速度相比,在运行时能够决定一次加速过程的成本可以忽略不计,那么只需编写您可以编写的最具可读性,最短和最简单的代码,剩下的就交给编译器-这就是它的工作。
两种方法的效率几乎相等。使用哪种方法应该没有区别