Question

Quelle est la meilleure façon d'utiliser NaN en C ++?

J'ai trouvé std::numeric_limits<double>::quiet_NaN() et std::numeric_limits<double>::signaling_NaN(). J'aimerais utiliser signaling_NaN pour représenter une variable non initialisée comme suit:

double diameter = std::numeric_limits<double>::signaling_NaN();

Ceci, cependant, signale (déclenche une exception) une assignation. Je veux qu'il lève une exception lors de l'utilisation, pas lors de la cession.

Existe-t-il un moyen d'utiliser <=> sans déclencher une exception lors de l'affectation? Existe-t-il une bonne alternative portable à <=> qui lève une exception de virgule flottante lorsqu’il est utilisé?

Était-ce utile?

La solution

Après un examen plus approfondi, il semble que signaling_NaN soit inutile comme prévu. Si les exceptions en virgule flottante sont activées, l'appel prend en compte le traitement d'un signal NaN de signalisation et déclenche immédiatement une exception. Si les exceptions en virgule flottante sont désactivées, le traitement d'un signal NaN de signalisation le rétrograde automatiquement en un signal NaN silencieux, de sorte que <=> ne fonctionne dans aucun cas.

Le code de Menkboy fonctionne, mais l'utilisation de la signalisation NaN pose d'autres problèmes: il n'y a pas de moyen portable d'activer ou de désactiver les exceptions en virgule flottante (comme indiqué dans ici et ici ), et si vous comptez sur les exceptions activées Un code tiers peut les désactiver (comme décrit ici ).

Il semble donc que la solution de Motti est vraiment le meilleur choix.

Autres conseils

La signalisation NAN signifie que lorsque la CPU le rencontre, un signal est déclenché (d'où son nom). Si vous souhaitez détecter des variables non initialisées, le relèvement du niveau d'avertissement de votre compilateur détecte généralement tous les chemins qui utilisent des valeurs non initialisées. Sinon, vous pouvez utiliser une classe wrapper qui stocke un dicton booléen si la valeur est initialisée:

template <class T>
class initialized {
    T t;
    bool is_initialized;
public:
    initialized() : t(T()), is_initialized(false) { }
    initialized(const T& tt) : t(tt), is_initialized(true) { }
    T& operator=(const T& tt) { t = tt; is_initialized = true; return t; }
    operator T&() {
         if (!is_initialized)
             throw std::exception("uninitialized");
         return t; 
   }
};

Vous pouvez écrire un NaN de signalisation dans une variable sans déclencher une exception avec quelque chose comme ceci (nb: non testé)

void set_snan( double &d )
{
    long long *bits = (long long *)&d;
    *bits = 0x7ff0000080000001LL;
}

Cela fonctionnera dans la plupart des endroits, mais non, ce n'est pas 100% portable.

Eh bien, en ce qui concerne la définition de NaN silencieux et signalant la signalisation, je ne peux vraiment pas faire la différence.

Vous pouvez utiliser vous-même le code utilisé dans ces fonctions, peut-être que cela empêche une exception de cette façon, mais je ne vois aucune exception dans ces deux fonctions, je pense que cela pourrait être lié à autre chose.

Si vous souhaitez attribuer directement le NaN:

double value = _Nan._Double;

Réponse simple: Faites quelque chose comme ceci dans le fichier d'en-tête et utilisez-le partout ailleurs:

#define NegativeNaN log(-1)

Si vous souhaitez effectuer certaines manipulations, écrivez une fonction de wrapper étendue autour de exp() comme extended_exp() et ainsi de suite!

Votre implémentation C ++ peut disposer d'une API permettant d'accéder à l'environnement en virgule flottante pour tester et effacer certaines exceptions en virgule flottante. Voir ma réponse à une question connexe pour plus d'informations.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top