我的代码如下:
void function(int parameter)
{
for( ... ) // a big loop
{
double a = ...;
for( ... ) // a big loop
{
double b = ...;
double value;
if(parameter == 1)
value = some_math_expression_1(a, b);
else if(parameter == 2)
value = some_math_expression_2(a, b);
...
}
}
}
我的想法是,根据参数,我想将一些数学表达式应用于a
和b
。这个函数执行很多次并且必须很快,我想知道每次迭代的那些条件分支是否会引入我可以节省的开销。
现在,我编写了这样的代码:
void function(int parameter)
{
if(parameter == 1)
function1();
else if(parameter == 2)
function2();
else
...
}
如果我在每个functionX()
中重复代码,那么我可以直接应用数学表达式。显而易见的问题是,当我想要更改某些代码时,我必须多次执行此操作(现在我有大约10个数学表达式)。
我可以使用哪种方法来避免function
中的任何开销?
如果我将函数some_math_expression_X
的指针传递给function
(我会更改函数调用的条件)怎么办?
如果我将整个函数编码为宏(uf)并将数学表达式设置为参数怎么办?
如果我使用模板并将数学表达式作为指向内联函数的指针传递(这是否可能),该怎么办?
编辑:谢谢您的回答。我知道我可以使用你提出的方法(指向/数组函数,或依赖于分支预测器)。但是,您是否对避免开销更好的方面有所了解?数学表达式非常简单(类似于a*b
),除了长的循环外,function
也被多次调用(分支预测在调用之间“存活”吗?)。
答案 0 :(得分:4)
您可以将该功能转换为模板:
void functionT<int PARAMETER>()
{
for( ... ) // a big loop
{
double a = ...;
for( ... ) // a big loop
{
double b = ...;
double value;
if(PARAMETER == 1) //Constant condition!!!
value = some_math_expression_1(a, b);
else if(PARAMETER == 2) //Constant condition!!!
value = some_math_expression_2(a, b);
...
}
}
}
由于条件始终为true或始终为false,因此编译器将优化条件树并仅保留实数表达式。没有分支,没有函数调用!
现在,您只能将其用于常量参数:
functionT<1>();
但不是变量:
int x = 1;
functionT<x>(); //Error
如果您需要,可以制作包装:
void function(int parameter)
{
switch (parameter)
{
case 1: functionT<1>(); break;
case 2: functionT<2>(); break;
}
}
答案 1 :(得分:3)
别担心。现代CPU具有分支预测器,它们将正确预测所采用的分支。
答案 2 :(得分:1)
您可以设置一个常量的函数指针数组,并调用与parameter
相关联的函数。
但是如果数学表达式相当小,那么switch()语句可能会更快。
switch (parameter) {
case 1:
value = math expression 1;
break;
case 2:
...
}
答案 3 :(得分:1)
首先,我会一如既往地说你应该基准测试这个过程现在需要多长时间,因为一如既往,这可能是过早的优化,你可能会发现这不是你的代码的一部分花了很长时间。
但假设您已经测量并发现这是代码中的瓶颈,我会做一些事情。
首先,正如你所说的那样,这里最能杀死你的东西(假设你的数学函数足够简单)就是分支预测。因此,为了摆脱分支,我将创建一个函数指针数组,而不是做
if(parameter == 1)
function1();
if...
你可以这样做:
array_of_functions[parameter]();
这将消除所有分支预测,并将大大增加吞吐量,因为您的管道不必刷新。编译器也应能够内联函数。
答案 4 :(得分:0)
这取决于很多东西,但一般来说你可能想要这样做,以便大多数时候连续调用第一个或第二个函数。这将使现代CPU执行速度更快(参见Why is it faster to process a sorted array than an unsorted array?)。
您可以使用数组和函数指针,但这可能无法加快速度,需要尝试。您可以使用http://www.boost.org/doc/libs/1_54_0/doc/html/function/tutorial.html#idp59212272来帮助您,但静态函数不需要它。
答案 5 :(得分:0)
我认为最有效的方法之一是创建一个函数指针数组,然后你可以直接传递函数指针而不仅仅是参数。这样可以节省在嵌套循环中使用if / switch语句时会产生的任何开销。
举个例子:
double expression_0(double a, double b) {...};
double expression_1(double a, double b) {...};
void function(double (*expression)(double, double)) {
for (...) {
...
double a = ...;
for (...) {
double b = ...;
double result = (*expression)(a, b);
}
}
}
int main() {
double (*fpointers[2]) (double, double);
fpointers[0] = expression_0;
fpointers[1] = expression_1;
int parameter = ...;
function(fpointers[parameter]);
}
答案 6 :(得分:0)
如果您的所有功能都具有相同的签名,那么最简单的方法就是:
void function(int parameter)
{
double ( *fn )( double, double );
switch( parameter )
{
case 1: fn = &some_math_expression_1; break;
case 2: fn = &some_math_expression_2; break;
...
}
for( ... ) // a big loop
{
double a = ...;
for( ... ) // a big loop
{
double b = ...;
double value = fn( a, b );
...
}
}
}