0

Concerning speed, if I need to calculate a large expression, say:

switch1*(large expression 1)+switch2*(large expression 2)

Depending on my input, switch1 can be 0 or 1, as can switch2 be. What would be the quickest for c++ to do, making an if statement or write it down as above?

bolov
  • 72,283
  • 15
  • 145
  • 224
Melissa
  • 31
  • 1
  • 1
    Please provide a [mcve], and you can check for yourself on godbolt – Passer By Jul 06 '17 at 07:25
  • If you're large expresssion contains function calls where the compiler can not say for sure that they have no side effects, they will not be optimized away. If either of the switches are not constant 0 values at compile time, also no optimization of the whole expression will happen. – Niklas R Jul 06 '17 at 07:25
  • 5
    Looks like premature optimization. First measure, then optimize. – Rakete1111 Jul 06 '17 at 07:25
  • 1
    It depends on what the expressions are. For example, can the compiler tell that they have no side-effects? – David Schwartz Jul 06 '17 at 07:27

5 Answers5

0

So, essentially you are asking about Short-Circuit Evaluation, and you are asking whether C++ does it for arithmetic expressions besides boolean expressions.

It is kind of hard to prove a negative, but as far as I know, C++ only does short-circuit evaluation for logical expressions, so there is no equivalent for arithmetic expressions. Also, I can think of plenty of code that would horribly break if arithmetic expressions were being evaluated in a short-circuit fashion, so I don't think that could ever be so.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
0

Theoretically, the compiler could generate code to avoid computing the expression if it could show that it had no side-effects. But in practice, it's unlikely to add code to check if the value is zero because it has no reason to think that it will be.

On the other hand, logical operations (|| and &&) are guaranteed to short-circuit in C++. So you should use them.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0
result = 0;
if(switch1) {
    result += large_expresion_1();
}
if(switch2)
    result += large_expression2();
}

But if you are optimising "large expressions" be sure to check whether it's actually quicker to calculate them both then add them in a branchless manner. eg something like

result = ((-(uint64_t)(switch1)) & large_expression_1) + ((-(uint64_t)(switch2)) & large_expression_2);

A bunch of such bithacks are documented here: https://graphics.stanford.edu/~seander/bithacks.html

Benchmark and separate to that, read the generated assembly language to find out what the compiler is actually doing for (or to) you.

Hal
  • 1,061
  • 7
  • 20
0

switch1 can be 0 or 1, as can switch2 be

If switch1 and switch2 can really only have values of 0 or 1 then it would be better for them to be booleans rather than integers.

With boolean switches, your statement becomes:

result = (switch1 ? (large expression 1) : 0)
       + (switch2 ? (large expression 2) : 0)

It is the case that in this form, the expressions will be computed even if their result won't be used. A simple and clear way to avoid wasted computation is the obvious one:

result = 0;
if(switch1) {
    result += large expression 1;
}
if(switch2) {
    result += large expression 2;
}

You could tidy this up by extracting methods, into which you pass the switches:

result = guardedLargeExpression1(switch1, otherparams1) 
       + guardedLargeExpression2(switch2, otherparams2);

... with ...

int guardedLargeExpression1(bool switch, foo params) {
    if(switch) {
        return 0;
    }
    return large expression(...);
}

You could also do clever stuff with pointers to functions:

int guardedFunctionCall(bool switch, int *functionptr(foo), foo arg) {
    if(switch) {
        return 0;
    }
    return (*functionptr)(arg);
}

... which is approaching the kind of thing you'd do in Java when you lazily evaluate code using a Supplier.

Or, since you're in C++ not C, you can do something more OO and actually use the C++ equivalent of Supplier: What is the C++ equivalent of a java.util.function.Supplier?

slim
  • 40,215
  • 13
  • 94
  • 127
0

If depends on the exact conditions. CPU, compiler, the exact expressions.

An if can slow down a program, if if becomes a conditional jump in the assembly code, and the condition cannot be predicted.

If the conditional cannot be predicted, and the "large expressions" are actually simple, it may be faster to do the "multiply-way".

However, if the expressions are slow to calculate, or the if can be branch predicted perfectly (or it doesn't compile to a conditional jump), then I think the if way will be faster.

All in all, you should try both solutions, and check which is faster.

geza
  • 28,403
  • 6
  • 61
  • 135