41 votes

Pourquoi est-Release/Debug avoir 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;
}

En Debug, j'obtiens:

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

Dans la Version, j'obtiens:

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

Pourquoi aurais-je obtenir un résultat différent dans la Version de Débogage?

J'ai déjà vérifié Débordement de Pile post Utilisation des fonctions min et max en C++, et il ne mentionne aucune Release/Debug différences.

Je suis à l'aide de Visual Studio 2015.

37voto

KrzaQ Points 1

Dans la norme IEEE 754 comparant NAN à quoi que ce soit sera toujours céder false, peu importe ce qu'elle est.

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

Et surtout, le plus important pour vous

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

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

Par exemple, ces fonctions pourrait être décrit comme tel

Libération:

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

Les exigences (LessThanComparable) sur std::min côté, ceux qui ont le même sens arithmétique. Mais ils aboutissent à des résultats différents lorsque vous les utilisez avec NaN.

26voto

jpo38 Points 1089

Eu:

Ici est la mise en œuvre utilisé par VS en mode Debug (avec _Pred être DEBUG_LT, LT pour Inférieur à):

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 est équivalent à (plus lisible):

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

Qui est équivalent à (!_Pred(_Left, _Right)). Transcrites sous forme d'une macro, il devient #define _DEBUG_LT(x, y) !((y) < (x)) (j'.e: PAS de droit < à gauche).

Communiqué de la mise en œuvre est en fait une macro #define _DEBUG_LT(x, y) ((x) < (y)) (j'.e: à gauche < droit).

Afin de Débogage (!(y<x)) et Relâchez - (x<y) des implémentations ne sont certainement pas les mêmes et ils ne se comportent différemment si un paramètre est un NaN...! Ne me demandez pas pourquoi ils l'ont fait....

22voto

user2079303 Points 4916

Vous n'avez pas à spécifier la représentation à virgule flottante au format de votre processeur utilise. Mais, puisque vous utilisez Visual Studio, je vais supposer que vous utilisez Windows, et puis je vais supposer que votre processeur utilise la norme IEEE 754 représentation.

Dans la norme IEEE 754, NaN n'est pas ordonné à l'égard de chaque numéro. Cela signifie qu' (NaN < f) == false et (f < NaN) == false pour toute valeur de f. Manière affectée, 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 l' std::min. Pratiquement std::min se comporte comme spécifié dans la norme en tant que aucun de ces arguments n'est NaN.

Depuis l'un des arguments est de NaN dans votre code, le résultat n'est pas spécifié par la norme - c'est peut-être l'un ou l'autre en fonction des facteurs externes, tels que la libération vs debug, la version du compilateur, de la phase de la lune, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X