What is the fastest way to find the maximum of two floats in C ++?
Here's another question
Why do you think that such a small optimization would matter in the larger context of your program?
I find it highly unlikely that micro-optimizations like this will have a measurable impact on your program. You should never micro-optimize like this unless the profiler specifically showed it to be a problem.
EDIT Add explanations to comments
The reason there isn't a big answer to this question is because the performance of this code is highly dependent on ...
- The way it was used in your program
- The specific compiler you are using
- Optimization flags passed to your compiler
- In a specific architecture, you use the code
- Many other very tiny things that were not included in the question
Even if all of this information were included, our answers would be speculations at best. The only way to answer this question is to pop out the profiler and see which is faster.
However, this is almost certainly not worth the effort. Micro-optimizing such a small part of your program will almost certainly not add any discernible advantage over your code. In general, it is a really bad idea to optimize such code, unless the profiler tells you so. Otherwise, you will spend a lot of time optimizing something without any acceptable benefits.
Yes, there are times when this kind of optimization can be important. But that would only be in special cases where the code was part of a very tight, highly called loop. However, the only way to identify such a code is to use a profiler.
a source to share
You can check this yourself on your system.
I did it for you on gcc-redhat. Results of my system, for 100,000 executions with x1 = 432943.5 and x2 = 434232.9
a) ~ 1200 μs b) ~ 600 μs c) ~ 600 μs
EDIT: When optimizing -O2, I got the same results in all three cases: ~ 110 μs.
Of course, the actual outcome will depend on many factors in your particular problem and system.
a source to share
-O3 Dual Core Macbook pro 2.4ghz
std :: max (x1, x2) Time: 4.19488 RMAAx: 4.19613 if time: 4.18775? Time: 4.18831
std :: max (x1, x2) Time: 4.1836 RMAAx: 4.18274 if time: 4.18603? Time: 4.18857
std :: max (x1, x2) Time: 4.18714 RMAAx: 4.18759 if time: 4.19752? Time: 4.19797
std :: max (x1, x2) Time: 4.1926 RMAAx: 4.19293 if time: 4.19334? Time: 4.19626
std :: max (x1, x2) Time: 4.18963 RMAAx: 4.19628 if time: 4.19253? Time: 4.19107
#include <iostream>
using namespace std;
int main (int argc, char * const argv[]) {
uint64_t iterations = 10000000000;
float x1 = 3455.232;
float x2 = 7456.856;
float y = 0;
for (int count = 0; count < 5; ++count)
{
clock_t begin_time = clock();
for (uint64_t ii = 0; ii < iterations; ++ii)
{
y = std::max(x1, x2);
}
std::cout << "std::max(x1, x2) Time: " << float( clock () - begin_time ) / CLOCKS_PER_SEC << endl;
begin_time = clock();
for (uint64_t ii = 0; ii < iterations; ++ii)
{
y = x1;
if (y < x2)
y = x2;
}
std::cout << "RMAAx : " << float( clock () - begin_time ) / CLOCKS_PER_SEC << endl;
begin_time = clock();
for (uint64_t ii = 0; ii < iterations; ++ii)
{
if (x1 > x2)
y = x1;
else
y = x2;
}
std::cout << "if Time: " << float( clock () - begin_time ) / CLOCKS_PER_SEC << endl;
begin_time = clock();
for (uint64_t ii = 0; ii < iterations; ++ii)
{
y = x1 > x2 ? x1 : x2;
}
std::cout << "? Time: " << float( clock () - begin_time ) / CLOCKS_PER_SEC << endl;
}
return 0;
}
a source to share
Intel x86 has instructions (FCOMI / FCOMIP / FUCOMI / FUCOMIP) that provide fast comparison of floating point values. Your CPU might also have instructions like this. The trick is figuring out what C ++ writes to maximize the chances of your compiler using these instructions, instead of doing something slower but more general.
An optimistic suggestion is to use std :: max (float, float) in the hope that someone else ignores those mocking "micro lens" and "premature optimization" and did the research needed to provide specialization for std :: max (float, float) which will use your hardware's specialized instructions.
a source to share
B and C will amount to the same, at least in theory. I choose them because if std::max
not a function call (like a macro) this will be the fastest.
Edit . Apparently std::max
is a call to a template function like your C form.
Http://www.cplusplus.com/reference/algorithm/max/
a source to share
Same observation as usual when it comes to "fastest". Have you measured the execution time of your maximum calculation being reported to the rest of the process execution time? Does this "optimization" decision have a significant impact on the runtime of your application?
I'm 99% sure the difference between your suggestions is not worth considering.
a source to share
First, as others have said, profile your code and make sure it's something worth optimizing. If so, read on: you can do it without forking. See Down with fcmp: Conditional Movements for Unrated Mathematics for more details.
a source to share
And this way could be better?
y = x1;
if (y < x2)
y = x2;
Removing the else clause can be better interpreted by the compiler.
Edit1: If benchmarking remember to do half of the test with x1 greater than x2 and the other half with x2 greater. Otherwise, the results do not reflect actual cases.
Edit2: Microoptimazions are somehow useful if you are working on embedded systems with 1 or 2k memory. And also, its an interesting problem to think about why the timings are different in each case.
a source to share
It is common to #define
use either b or c as a macro, and use it throughout your code. Note that this only works in most cases and will die if you pass an x or y argument modified by a non-idempotent operator or a function call with side effects. For instance:
#define MAX(x,y) (((x) < (y)) ? (y) : (x))
...
MAX(i++, ++j); //won't work properly, the ++ will get executed twice.
MAX(changeKSomehow(k), changeLSomehow(L)); //won't work, the functions will get called twice.
It turns out std :: max, at least for GNU libstdc ++, is implemented in almost the same way and uses a hint inline
. The compiler should be able to take a hint when needed (when the <operator takes multiple instructions, so as not to impose a huge amount of i $ -pressure if it was inlined).
a source to share