web-dev-qa-db-fra.com

Pourquoi Release / Debug a un résultat différent pour std :: min?

Voici le programme de test:

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

Dans Debug, j'obtiens:

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

En version, j'obtiens:

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

Pourquoi obtiendrais-je un résultat différent dans la version que dans le débogage?

J'ai déjà vérifié le post Stack Overflow tilisation des fonctions min et max en C++, et il ne mentionne aucune différence Release/Debug .

J'utilise Visual Studio 2015.

42
jpo38

Je l'ai:

Voici l'implémentation utilisée par VS en mode débogage (avec _Pred Étant DEBUG_LT, LT pour 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);
    }

Ce qui équivaut à (plus lisible):

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

Ce qui, encore une fois, équivaut à (!_Pred(_Left, _Right)). Transcrite sous forme de macro, elle devient #define _DEBUG_LT(x, y) !((y) < (x)) (c'est-à-dire: PAS droite <gauche).

L'implémentation des versions est en fait une macro #define _DEBUG_LT(x, y) ((x) < (y)) (c'est-à-dire: gauche <droite).

Les implémentations Debug (!(y<x)) Et Release (x<y) Ne sont donc certainement pas les mêmes et se comportent différemment si un paramètre est un NaN ...! Ne demandez pas pourquoi ils ont fait ça ...

27
jpo38

Dans IEEE 754 comparer NAN à n'importe quoi donnera toujours false, peu importe ce que c'est.

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

Et, plus important encore pour vous

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

Il semble donc que le compilateur réorganise les paramètres/utilise > ou <= au lieu de <, et c'est pourquoi vous obtenez des résultats différents.

Par exemple, ces fonctions pourraient être décrites comme telles

Libération:

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

Déboguer:

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

Les exigences (LessThanComparable) sur std::min à part, ceux-ci ont la même signification arithmétiquement. Mais ils donnent des résultats différents lorsque vous les utilisez avec NaN.

38
krzaq

Vous n'avez pas spécifié le format de représentation en virgule flottante utilisé par votre processeur. Mais, puisque vous utilisez Visual Studio, je suppose que vous utilisez Windows, puis je suppose que votre processeur utilise la représentation IEEE 754 .

Dans IEEE 754, NaN n'est pas ordonné pour chaque numéro. Cela signifie que (NaN < f) == false et (f < NaN) == false pour toute valeur de f. Pédantiquement, cela signifie que les nombres à virgule flottante qui prennent en charge NaN ne répondent pas aux exigences de LessThanComparable qui est une exigence pour std::min. Pratiquement std::min se comporte comme spécifié dans la norme tant qu'aucun des arguments n'est NaN.

Étant donné que l'un des arguments est NaN dans votre code, le résultat n'est pas spécifié par la norme - il pourrait être l'un ou l'autre en fonction de facteurs externes tels que la version vs la version de débogage, la version du compilateur, la phase de la lune, etc.

23
eerorika