Here is the test program:
void testFunc()
{
double maxValue = DBL_MAX;
double slope = std::numeric_limits<double>::quiet_NaN();
std::cout << "slope is " << slope << std::endl;
std::cout << "maxThreshold is " << maxValue << std::endl;
std::cout << "the_min is " << std::min( slope, maxValue) << std::endl;
std::cout << "the_min is " << std::min( DBL_MAX, std::numeric_limits<double>::quiet_NaN()) << std::endl;
}
int main( int argc, char* argv[] )
{
testFunc();
return 0;
}
In Debug, I get:
slope is nan
maxThreshold is 1.79769e+308
the_min is nan
the_min is 1.79769e+308
In Release, I get:
slope is nan
maxThreshold is 1.79769e+308
the_min is 1.79769e+308
the_min is nan
Why would I get a different result in Release than Debug?
I already checked Stack Overflow post Use of min and max functions in C++, and it does not mention any Release/Debug differences.
I am using Visual Studio 2015.
In IEEE 754 comparing NAN to anything will always yield
false
, no matter what it is.And, more importantly for you
So it seems that the compiler reorders the parameters/uses
>
or<=
instead of<
, and that's why you get the differing results.For example, those functions could be described as such
Release:
Debug:
The requirements (LessThanComparable) on
std::min
aside, those have the same meaning arithmetically. But they yield different results when you use them with NaN.You didn't specify which floating point representation format your processor uses. But, since you use Visual Studio, I'll assume that you use Windows, and then I'll assume that your processor uses IEEE 754 representation.
In IEEE 754, NaN is unordered in respect to every number. This means that
(NaN < f) == false
and(f < NaN) == false
for any value off
. Pedantically, this means that floating point numbers that support NaN do not meet the requirements of LessThanComparable which is a requirement forstd::min
. Practicallystd::min
behaves as specified in the standard as long as neither argument is NaN.Since one of the arguments is NaN in your code, the result is unspecified by the standard - it could be one or the other depending on any external factors such as release vs debug build, version of compiler, phase of the moon, etc.
Got it:
Here is the implementation used by VS in Debug mode (with
_Pred
beingDEBUG_LT
, LT for Lower Than):Which is equivalent to (more readable):
Which, again is equivalent to
(!_Pred(_Left, _Right))
. Transcripted as a macro, it becomes#define _DEBUG_LT(x, y) !((y) < (x))
(i.e: NOT right < left).Release implementation is actually a macro
#define _DEBUG_LT(x, y) ((x) < (y))
(i.e: left < right).So Debug
(!(y<x))
and Release(x<y)
implementations are definitely not the same and they do behave differently if one parameter is a NaN...! Don't ask why they did that....