For people who wonder even more about taking the maximum of two floats: let's
compare fmax(a,b)
, fmaxf(a,b)
, std::max(a,b)
and if (a < b) return b; else return a;
in gcc, clang, icc and msvc.
Look at the assembler outputs here: gcc and clang (https://godbolt.org/z/a1pb5N), icc and mscv (https://godbolt.org/z/FoH15I).
Results:
. | CLANG | GCC | ICC | MSVC |
---|---|---|---|---|
fmax | double, wtf, maxsd | double, call fmax | double, call fmax | call fmaxf |
fmaxf | wtf, maxss | call fmaxf | call fmaxf | call fmaxf |
std::max | maxss | maxss | maxss | maxss |
if(<) | maxss | maxss | maxss | conditional |
Discussion of the four implementations:
- fmax() has signature
double fmax(double, double)
, and only MSVC is sneaky enough to ignore that. However, since you're working with floats, not doubles, please just use fmaxf(). - fmaxf() results in a function call (!) in all but clang, but clang uses something weird with cmpunordss; see below.
- std::max() uses the optimal single maxss instruction in all compilers. Please use this one.
- The if-condition is recognised and converted to the optimal maxss instruction by all the smart compilers in the bunch; only msvc outputs an actual branch.
Further remarks:
- Clang is the only compiler that inlines fmax() and fmaxf(), and it shows that these functions are paranoid: the cmpunordss is an instruction that allows it to deal correctly with NaN values. Indeed, the specification of the functions states that NaN is treated as -inf. The std::max() and if(<) implementations don't have this particular behaviour with NaN's.
- MSVC is not smart enough to recognise the conditional and convert it to a maximum instruction. Poor msvc.
- Clang may actually be the best compiler in this micro-test: for all four implementations, it's as good or better than the rest. (Note that a function call is always undesirable in hot code.)
Conclusion: use std::max().