ここにテストプログラムがあります:
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を使用しています。
とった:
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である場合、それらは異なる動作をします...!彼らがそれをした理由を聞かないでください...
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で使用すると、異なる結果が得られます。
プロセッサが使用する浮動小数点表現形式を指定していません。ただし、Visual Studioを使用しているので、Windowsを使用していると仮定し、次に、プロセッサーが IEEE 754 表現を使用していると仮定します。
IEEE 754では、NaNはすべての数値に関して無秩序です。これは、f
の任意の値に対して(NaN < f) == false
および(f < NaN) == false
を意味します。つまり、NaNをサポートする浮動小数点数は、std::min
の要件である LessThanComparable の要件を満たしていません。どちらの引数もNaNでない限り、実際にはstd::min
は規格で指定されたとおりに動作します。
引数の1つはコードのNaNであるため、結果は標準では規定されていません。リリースとデバッグビルド、コンパイラのバージョン、月の満ち欠けなどの外部要因に応じて、どちらか一方になる可能性があります。