6

20-30 years ago arithmetic operations like division were one of the most costly operations for CPUs. Saving one division in a piece of repeatedly called code was a significant performance gain. But today CPUs have fast arithmetic operations and since they heavily use instruction pipelining, conditionals can disrupt efficient execution. If I want to optimize code for speed, should I prefer arithmetic operations in favor of conditionals?

Example 1

Suppose we want to implement operations modulo n. What will perform better:

int c = a + b;
result = (c >= n) ? (c - n) : c;

or

result = (a + b) % n;

?

Example 2

Let's say we're converting 24-bit signed numbers to 32-bit. What will perform better:

int32_t x = ...;
result = (x & 0x800000) ? (x | 0xff000000) : x;

or

result = (x << 8) >> 8;

?

Petr
  • 62,528
  • 13
  • 153
  • 317
  • 2
    To the "let the compiler handle it" crowd: I challenge you to find one compiler that will generate the same code for Example #1 given `int a = rand() % n, b = rand() % n;` – Ben Voigt Feb 09 '13 at 16:45

3 Answers3

3

If you want to optimise for speed, you should just tell your compiler to optimise for speed. Modern compilers will generally outperform you in this area.

I've sometimes been surprised trying to relate assembly code back to the original source for this very reason.

Optimise your source code for readability and let the compiler do what it's best at.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 2
    Only if you have no information the compiler doesn't. Many optimizations are valid only for a limited range of inputs. If you know that constraint is satisfied and the compiler doesn't, you need to do the optimization yourself. And compiler writers sometimes won't spend time on such transformations at all, simply because they aren't universally usable. – Ben Voigt Feb 09 '13 at 16:39
3

All the low hanging fruits are already picked and pickled by authors of compilers and guys who build hardware. If you are the kind of person who needs to ask such question, you are unlikely to be able to optimize anything by hand.

While 20 years ago it was possible for a relatively competent programmer to make some optimizations by dropping down to assembly, nowadays it is the domain of experts, specializing in the target architecture; also, optimization requires not only knowing the program, but knowing the data it will process. Everything comes down to heuristics, tests under different conditions etc.

Simple performance questions no longer have simple answers.

fdreger
  • 12,264
  • 1
  • 36
  • 42
  • He's not writing assembly here. – Ben Voigt Feb 09 '13 at 16:30
  • 1
    @BenVoigt: and yet my answer holds. – fdreger Feb 09 '13 at 16:39
  • 2
    Only for really low-level things. Replacement of algorithm with a lower complexity is still a very desirable optimization and one the compiler isn't yet able to do for you. Conditionally-valid optimizations are another sticky point where the programmer does have to get involved, either with manual optimization or manual tagging of preconditions. – Ben Voigt Feb 09 '13 at 16:43
  • 2
    @BenVoigt: yes, you are right, but - in the light of the question - the points are irrelevant. The answer to the questions is: "impossible to tell, not knowing the exact cpu, the way results will be used down the code, compiler, phase of the moon etc". Even simplest hoisting can change outcomes. – fdreger Feb 10 '13 at 14:03
3

I expect that in example #1, the first will perform better. The compiler will probably apply some bit-twiddling trick to avoid a branch. But you're taking advantage of knowledge that it's extremely unlikely that the compiler can deduce: namely that the sum is always in the range [0:2*n-2] so a single subtraction will suffice.

For example #2, the second way is both faster on modern CPUs and simpler to follow. A judicious comment would be appropriate in either version. (I wouldn't be surprised to see the compiler convert the first version into the second.)

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720