I have a code that looks like this:
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);
...
}
}
}
The idea is that depending on the parameter I want to apply some math expression to a
and b
. This function is executed many times and must be fast, and I wonder if those conditional branches at each iteration can introduce an overhead that I could save.
Right now, I have written the code like this:
void function(int parameter)
{
if(parameter == 1)
function1();
else if(parameter == 2)
function2();
else
...
}
So that I can apply the math expression directly if I repeat the code in every functionX()
. The obvious problem is that when I want to change some piece of code I have to do it several times (I have around 10 math expressions now).
What approach could I use to avoid any overhead in function
?
What if I pass a pointer to functions some_math_expression_X
to function
(I would change the conditionals for function invocations)?
What if I code the whole function as a macro (uf) and set the math expression as a parameter?
What if I use a template and pass the math expression as a pointer to an inline function (is this even possible)?
EDIT: Thank you for your answers. I know I can use the methods you are proposing (pointers to / array of functions, or relying on the branch predictor). However, do you have some insight about what would be better in terms of avoiding overhead? The math expressions are quite simple (something like a*b
), and in addition to the loops that are long, function
is also called many times (do branch predictions "survive" between calls?).
You can convert the function into a template:
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);
...
}
}
}
Since the conditions are always true or always false, the compiler will optimize the condition tree away and leave only the real math expression. No branches and no function calls!
Now, you can use it only with constant parameters:
functionT<1>();
But not with variables:
int x = 1;
functionT<x>(); //Error
If you need that, you can make a wrapper:
void function(int parameter)
{
switch (parameter)
{
case 1: functionT<1>(); break;
case 2: functionT<2>(); break;
}
}
Don't worry. Modern CPU's have branch predictors, and they will correctly predict the branch taken.
You could set up a constant array of function pointers, and call the function associated with parameter
.
But if the math expressions are rather small, a switch() statement could be even faster.
switch (parameter) {
case 1:
value = math expression 1;
break;
case 2:
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With