Reputation: 3652
In C++, are std::min
and std::max
preferable over fmin
and fmax
? For comparing two integers, do they provide basically the same functionality?
Do you tend to use one of these sets of functions or do you prefer to write your own (perhaps to improve efficiency, portability, flexibility, etc.)?
The C++ Standard Template Library (STL) declares the min
and max
functions in the standard C++ algorithm
header.
The C standard (C99) provides the fmin
and fmax
function in the standard C math.h
header (also provided in C++11 as std::fmin
and std::fmax
in the cmath
header).
Upvotes: 89
Views: 356608
Reputation: 33709
There is an important difference between std::min
, std::max
and fmin
and fmax
.
std::min(-0.0,0.0) = -0.0
std::max(-0.0,0.0) = -0.0
whereas
fmin(-0.0, 0.0) = -0.0
fmax(-0.0, 0.0) = 0.0
So std::min
is not a 1-1 substitute for fmin
. The functions std::min
and std::max
are not commutative. To get the same result with doubles with fmin
and fmax
, one should swap the arguments
fmin(-0.0, 0.0) = std::min(-0.0, 0.0)
fmax(-0.0, 0.0) = std::max( 0.0, -0.0)
But as far as I can tell all these functions are implementation defined anyway in this case so to be 100% sure you have to test how they are implemented.
There is another important difference. For x ! = NaN
:
std::max(Nan,x) = NaN
std::max(x,NaN) = x
std::min(Nan,x) = NaN
std::min(x,NaN) = x
whereas
fmax(Nan,x) = x
fmax(x,NaN) = x
fmin(Nan,x) = x
fmin(x,NaN) = x
fmax
can be emulated with the following code
double myfmax(double x, double y)
{
// after the next two comparisons, x and y are equivalent or there is NaN
if(x < y) return y;
if(y < x) return x;
// z > nan for z != nan is required by C the standard
if(std::isnan(x)) return y;
if(std::isnan(y)) return x;
// +0 > -0 is preferred by C the standard
if(std::signbit(x)) return y;
else return x;
}
std::max
is a subset of fmax
because it only needs the first comparison (x < y
).
Looking at the assembly shows that Clang uses builtin code for fmax
and fmin
whereas GCC calls them from a math library. The assembly for clang for fmax
with -O3
is
movapd xmm2, xmm0
cmpunordsd xmm2, xmm2
movapd xmm3, xmm2
andpd xmm3, xmm1
maxsd xmm1, xmm0
andnpd xmm2, xmm1
orpd xmm2, xmm3
movapd xmm0, xmm2
whereas for std::max(double, double)
it is simply
maxsd xmm0, xmm1
However, for GCC and Clang using -Ofast
fmax
becomes simply
maxsd xmm0, xmm1
So this shows once again that std::max
is a subset of fmax
and that when you use a looser floating point model which does not have nan
or signed zero then fmax
and std::max
are the same. The same argument obviously applies to fmin
and std::min
.
Upvotes: 56
Reputation: 1
The key difference is in the types of values they operate on. std::min
and std::max
are more general and can be used with various data types, while fmin
and fmax
are specifically designed for floating-point numbers. If you are working with integers or other types, you should use std::min
and std::max
.
Upvotes: -1
Reputation: 40199
In short, std::max
is a "generic function" from the <algotithm>
library that simply chooses the lower of two arguments according to the <
operator, whereas std::fmax
is specific to floating-point numbers and treats NaN as missing data.
std::fmax
/std::fmin
The contents and meaning of the header
<cmath>
are the same as the C standard library header<math.h>
[...]
- C++23 standard : [cmath.syn] p1
If just one argument is a
NaN
, thefmax
functions return the other argument (if both arguments areNaN
s, the functions return aNaN
).
[...]
The body of thefmax
function might be{ return (isgreaterequal(x, y) || isnan(y)) ? x : y; }
- C17 standard: F.10.9.2 The fmax functions
It's also worth noting that fmax
/fmin
may be sensitive to the sign of zero:
Ideally,
fmax
would be sensitive to the sign of zero, for examplefmax(−0.0, +0.0)
would return+0
; however, implementation in software might be impractical.
std::max
/std::min
template<class T> constexpr const T& max(const T& a, const T& b); // [...]
Preconditions: For the first form, T meets the Cpp17LessThanComparable requirements (Table 29).
Returns: The larger value. Returns the first argument when the arguments are equivalent.
There is no sample implementation in the standard, but a possible implementation looks like:
{ return a < b ? b : a; }
For performance reasons, it is better to use std::max
and std::min
.
On modern x86_64, std::max
compiles to a single instruction
vmaxss xmm0, xmm1, xmm0 ; xmm0 = max(xmm1, xmm0)
... whereas std::fmax
compiles to
vmaxss xmm2, xmm1, xmm0 ; xmm2 = max(xmm1, xmm0)
vcmpunordss xmm0, xmm0, xmm0 ; test xmm0 for NaN, set mask bits
vblendvps xmm0, xmm2, xmm1, xmm0 ; xmm0 = isnan(xmm0) ? xmm1 : xmm2
See Compiler Explorer.
If there's no possibility of operands being NaN, you should go for std::max
/std::min
. Otherwise, use std::fmax
/std::fmin
.
std::fmax(x, y)
cannot be implemented using only vmaxss dest, y, x
because if x
or y
is NaN, dest = x
. std::fmax
chooses x
or y
depending on which one isn't NaN. vmaxss
is biased towards x
in every possible way.
However, vmaxss
matches the behavior of x < y ? y : x
and thus std::max
exactly.
Upvotes: 0
Reputation: 23237
fmin
and fmax
are specifically for use with floating point numbers (hence the "f"). If you use it for ints, you may suffer performance or precision losses due to conversion, function call overhead, etc. depending on your compiler/platform.
std::min
and std::max
are template functions (defined in header <algorithm>
) which work on any type with a less-than (<
) operator, so they can operate on any data type that allows such a comparison. You can also provide your own comparison function if you don't want it to work off <
.
This is safer since you have to explicitly convert arguments to match when they have different types. The compiler won't let you accidentally convert a 64-bit int into a 64-bit float, for example. This reason alone should make the templates your default choice. (Credit to Matthieu M & bk1e)
Even when used with floats the template may win in performance. A compiler always has the option of inlining calls to template functions since the source code is part of the compilation unit. Sometimes it's impossible to inline a call to a library function, on the other hand (shared libraries, absence of link-time optimization, etc.).
Upvotes: 123
Reputation: 185
Couldn't a C++ implementation targeted for processors with SSE instructions provide specializations of std::min and std::max for types float, double, and long double which do the equivalent of fminf, fmin, and fminl, respectively?
The specializations would provide better performance for floating-point types while the general template would handle non-floating-point types without attempting to coerce floating-point types into floating-point types that way the fmins and fmaxes would.
Upvotes: 0
Reputation: 16840
I would prefer the C++ min/max functions, if you are using C++, because they are type-specific. fmin/fmax will force everything to be converted to/from floating point.
Also, the C++ min/max functions will work with user-defined types as long as you have defined operator< for those types.
HTH
Upvotes: 4
Reputation: 133
By the way, in cstdlib
there are __min
and __max
you can use.
For more: http://msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx
Upvotes: 1
Reputation: 181
You're missing the entire point of fmin and fmax. It was included in C99 so that modern CPUs could use their native (read SSE) instructions for floating point min and max and avoid a test and branch (and thus a possibly mis-predicted branch). I've re-written code that used std::min and std::max to use SSE intrinsics for min and max in inner loops instead and the speed-up was significant.
Upvotes: 18
Reputation: 38962
As Richard Corden pointed, use C++ functions min and max defined in std namespace. They provide type safety, and help to avoid comparing mixed types (i.e. float point vs integer) what sometimes may be undesirable.
If you find that C++ library you use defines min/max as macros as well, it may cause conflicts, then you can prevent unwanted macro substitution calling the min/max functions this way (notice extra brackets):
(std::min)(x, y)
(std::max)(x, y)
Remember, this will effectively disable Argument Dependant Lookup (ADL, also called Koenig lookup), in case you want to rely on ADL.
Upvotes: 3
Reputation: 21731
Use std::min
and std::max
.
If the other versions are faster then your implementation can add overloads for these and you'll get the benefit of performance and portability:
template <typename T>
T min (T, T) {
// ... default
}
inline float min (float f1, float f2) {
return fmin( f1, f2);
}
Upvotes: 0
Reputation: 45533
fmin
and fmax
, of fminl
and fmaxl
could be preferred when comparing signed and unsigned integers - you can take advantage of the fact that the entire range of signed and unsigned numbers and you don't have to worry about integer ranges and promotions.
unsigned int x = 4000000000;
int y = -1;
int z = min(x, y);
z = (int)fmin(x, y);
Upvotes: -1
Reputation: 490693
If your implementation provides a 64-bit integer type, you may get a different (incorrect) answer by using fmin or fmax. Your 64-bit integers will be converted to doubles, which will (at least usually) have a significand that's smaller than 64-bits. When you convert such a number to a double, some of the least significant bits can/will be lost completely.
This means that two numbers that were really different could end up equal when converted to double -- and the result will be that incorrect number, that's not necessarily equal to either of the original inputs.
Upvotes: 6
Reputation: 320777
As you noted yourself, fmin
and fmax
were introduced in C99. Standard C++ library doesn't have fmin
and fmax
functions. Until C99 standard library gets incorporated into C++ (if ever), the application areas of these functions are cleanly separated. There's no situation where you might have to "prefer" one over the other.
You just use templated std::min
/std::max
in C++, and use whatever is available in C.
Upvotes: 2
Reputation: 12620
fmin and fmax are only for floating point and double variables.
min and max are template functions that allow comparison of any types, given a binary predicate. They can also be used with other algorithms to provide complex functionality.
Upvotes: 0
Reputation: 28127
std::min and std::max are templates. So, they can be used on a variety of types that provide the less than operator, including floats, doubles, long doubles. So, if you wanted to write generic C++ code you'd do something like this:
template<typename T>
T const& max3(T const& a, T const& b, T const& c)
{
using std::max;
return max(max(a,b),c); // non-qualified max allows ADL
}
As for performance, I don't think fmin
and fmax
differ from their C++ counterparts.
Upvotes: 6
Reputation: 1934
I always use the min and max macros for ints. I'm not sure why anyone would use fmin or fmax for integer values.
The big gotcha with min and max is that they're not functions, even if they look like them. If you do something like:
min (10, BigExpensiveFunctionCall())
That function call may get called twice depending on the implementation of the macro. As such, its best practice in my org to never call min or max with things that aren't a literal or variable.
Upvotes: -1