Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Release/Debug have a different result for std::min?

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.

like image 402
jpo38 Avatar asked Oct 07 '16 13:10

jpo38


People also ask

What is difference between release and debug mode?

By default, Debug includes debug information in the compiled files (allowing easy debugging) while Release usually has optimizations enabled. As far as conditional compilation goes, they each define different symbols that can be checked in your program, but they are language-specific macros.

Can you debug in release mode?

You can now debug your release build application. To find a problem, step through the code (or use Just-In-Time debugging) until you find where the failure occurs, and then determine the incorrect parameters or code.


2 Answers

In IEEE 754 comparing NAN to anything will always yield false, no matter what it is.

slope > 0; // false slope < 0; // false slope == 0; // false 

And, more importantly for you

slope < DBL_MAX; // false DBL_MAX < slope; // false 

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:

double const& min(double const& l, double const r) {     return l <= r ? l : r; } 

Debug:

double const& min(double const& l, double const& r) {     return r < l ? r : l; } 

The requirements (LessThanComparable) on std::min aside, those have the same meaning arithmetically. But they yield different results when you use them with NaN.

like image 123
krzaq Avatar answered Sep 26 '22 08:09

krzaq


Got it:

Here is the implementation used by VS in Debug mode (with _Pred being DEBUG_LT, LT for Lower Than):

template<class _Pr,     class _Ty1,     class _Ty2> inline     _CONST_FUN bool _Debug_lt_pred(_Pr _Pred,         _Ty1&& _Left, _Ty2&& _Right,         _Dbfile_t _File, _Dbline_t _Line)     {   // test if _Pred(_Left, _Right) and _Pred is strict weak ordering     return (!_Pred(_Left, _Right)         ? false         : _Pred(_Right, _Left)             ? (_DEBUG_ERROR2("invalid comparator", _File, _Line), true)             : true);     } 

Which is equivalent to (more readable):

    if (!_Pred(_Left, _Right))     {         return false;     }     else     {         if ( _Pred(_Right, _Left) )         {             assert( false );             return true;         }         else         {             return true;         }     } 

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....

like image 44
jpo38 Avatar answered Sep 24 '22 08:09

jpo38