web-dev-qa-db-ja.com

リリース/デバッグのstd :: minの結果が異なるのはなぜですか?

ここにテストプログラムがあります:

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

リリースではデバッグとは異なる結果になるのはなぜですか?

私はすでにスタックオーバーフローの投稿C++でのminおよびmax関数の使用を確認しましたが、リリース/デバッグの違いについては触れていません。

Visual Studio 2015を使用しています。

42
jpo38

とった:

VSがデバッグモードで使用する実装は次のとおりです(__Pred_は_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);
    }
_

これは(より読みやすい)と同等です:

_    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))になります(つまり、右<左ではありません)。

リリースの実装は実際にはマクロ#define _DEBUG_LT(x, y) ((x) < (y))です(つまり、左<右)。

したがって、デバッグ_(!(y<x))_とリリース_(x<y)_の実装は完全に同じではなく、1つのパラメーターがNaNである場合、それらは異なる動作をします...!彼らがそれをした理由を聞かないでください...

27
jpo38

IEEE 754 では、NANを何かと比較すると、何であろうと常にfalseが得られます。

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

そして、あなたにとってもっと重要なのは

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

したがって、コンパイラはパラメータを並べ替えたり、>の代わりに<=または<を使用したりするように見えます。そのため、異なる結果が得られます。

たとえば、それらの機能はそのように説明できます

リリース:

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

std::minの要件(LessThanComparable)は別にして、それらは算術的に同じ意味を持っています。ただし、NaNで使用すると、異なる結果が得られます。

38
krzaq

プロセッサが使用する浮動小数点表現形式を指定していません。ただし、Visual Studioを使用しているので、Windowsを使用していると仮定し、次に、プロセッサーが IEEE 754 表現を使用していると仮定します。

IEEE 754では、NaNはすべての数値に関して無秩序です。これは、fの任意の値に対して(NaN < f) == falseおよび(f < NaN) == falseを意味します。つまり、NaNをサポートする浮動小数点数は、std::minの要件である LessThanComparable の要件を満たしていません。どちらの引数もNaNでない限り、実際にはstd::minは規格で指定されたとおりに動作します。

引数の1つはコードのNaNであるため、結果は標準では規定されていません。リリースとデバッグビルド、コンパイラのバージョン、月の満ち欠けなどの外部要因に応じて、どちらか一方になる可能性があります。

23
eerorika