42

这是测试程序:

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;
}

在调试中,我得到:

slope is nan
maxThreshold is 1.79769e+308
the_min is nan
the_min is 1.79769e+308

在发布中,我得到:

slope is nan
maxThreshold is 1.79769e+308
the_min is 1.79769e+308
the_min is nan

为什么我会在 Release 中得到与 Debug 不同的结果?

我已经检查了 Stack Overflow post Use of min and max functions in C++,它没有提到任何发布/调试差异。

我正在使用 Visual Studio 2015。

4

3 回答 3

39

IEEE 754中,将 NAN 与任何东西进行比较总是会产生false,无论它是什么。

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

而且,对你来说更重要的是

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

因此,编译器似乎重新排序了参数/使用>or<=而不是<,这就是您得到不同结果的原因。

例如,这些功能可以这样描述

发布:

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

调试:

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

除了要求(LessThanComparable)std::min之外,它们在算术上具有相同的含义。但是当您将它们与 NaN 一起使用时,它们会产生不同的结果。

于 2016-10-07T14:06:49.307 回答
27

知道了:

这是 VS 在 Debug 模式下使用的实现(使用_Predbe DEBUG_LT, LT 表示低于):

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);
    }

这相当于(更具可读性):

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

其中,再次等价于(!_Pred(_Left, _Right))。转录为宏,它变成#define _DEBUG_LT(x, y) !((y) < (x))(即:NOT right < left)。

发布实现实际上是一个宏#define _DEBUG_LT(x, y) ((x) < (y))(即:left < right)。

所以 Debug(!(y<x))和 Release(x<y)实现肯定是不一样的,如果一个参数是 NaN,它们的行为会有所不同......!不要问他们为什么这样做......

于 2016-10-07T14:37:24.500 回答
23

您没有指定处理器使用哪种浮点表示格式。但是,由于您使用 Visual Studio,我将假设您使用 Windows,然后我将假设您的处理器使用IEEE 754表示。

在 IEEE 754 中,NaN 对于每个数字都是无序的。这意味着(NaN < f) == false并且(f < NaN) == false对于 的任何值f。迂腐地,这意味着支持 NaN 的浮点数不满足LessThanComparable的要求,这是std::min. std::min只要两个参数都不是 NaN,实际上就按照标准中的规定行事。

由于您的代码中的参数之一是 NaN,因此标准未指定结果 - 它可能是一个或另一个,具体取决于任何外部因素,例如发布与调试构建、编译器版本、月相等。

于 2016-10-07T14:18:41.507 回答