Existe-t-il une fonction isnan() ?
PS. : Je suis dans MinGW (si cela fait une différence).
J'ai résolu le problème en utilisant isnan() à partir de <math.h>
qui n'existe pas dans <cmath>
ce que j'étais #include
au début.
Existe-t-il une fonction isnan() ?
PS. : Je suis dans MinGW (si cela fait une différence).
J'ai résolu le problème en utilisant isnan() à partir de <math.h>
qui n'existe pas dans <cmath>
ce que j'étais #include
au début.
Selon la norme IEEE, les valeurs NaN ont la propriété étrange que les comparaisons qui les impliquent sont toujours faux. C'est-à-dire, pour un flotteur f, f != f
sera vrai uniquement si f est NaN.
Notez que, comme certains commentaires ci-dessous l'ont souligné, tous les compilateurs ne respectent pas cela lorsqu'ils optimisent le code.
Pour tout compilateur qui prétend utiliser la virgule flottante IEEE, cette astuce devrait travail. Mais je ne peux pas garantir que ça sera le travail en pratique. En cas de doute, vérifiez auprès de votre compilateur.
N'est-il pas possible que le compilateur l'optimise ? (Je ne sais pas car je n'ai pas utilisé le C++ depuis longtemps).
Le compilateur a intérêt à ne pas supprimer cette option s'il fonctionne en mode IEEE. Vérifiez la documentation de votre compilateur, bien sûr...
Le compilateur ne l'optimisera pas. La seule réserve est que cette propriété s'applique aux valeurs à virgule flottante IEEE, mais peut ne pas s'appliquer à d'autres formats. Les plates-formes courantes utilisent IEEE, donc le fonctionnement est garanti sur celles-ci, mais sur les plates-formes utilisant des formats de virgule flottante différents, cette astuce ne fonctionne pas.
Il n'y a pas isnan()
disponible dans la bibliothèque standard C++ actuelle. Elle a été introduite dans C99 et défini comme un macro pas une fonction. Les éléments de la bibliothèque standard définie par C99 ne font pas partie de la norme C++ actuelle ISO/IEC 14882:1998 ni de sa mise à jour ISO/IEC 14882:2003.
En 2005, le rapport technique 1 a été proposé. Le TR1 apporte la compatibilité avec C99 à C++. Malgré le fait qu'il n'a jamais été officiellement adopté pour devenir un standard C++, de nombreux ( GCC 4.0+. o Visual C++ 9.0 et plus Les implémentations C++ fournissent des fonctionnalités TR1, toutes ou seulement certaines (Visual C++ 9.0 ne fournit pas les fonctions mathématiques C99).
Si TR1 est disponible, alors cmath
comprend des éléments C99 comme isnan()
, isfinite()
etc. mais ils sont définis comme des fonctions, et non comme des macros, généralement dans std::tr1::
bien que de nombreuses implémentations (par exemple, GCC 4+ sous Linux ou XCode sous Mac OS X 10.5+) les injectent directement dans l'espace de nom std::
donc std::isnan
est bien défini.
De plus, certaines implémentations de C++ font encore du C99 isnan()
disponible pour C++ (inclus par le biais de cmath
o math.h
), ce qui peut causer plus de confusions et les développeurs peuvent supposer que c'est un comportement standard.
Une remarque à propos de Viusal C++, comme mentionné ci-dessus, il ne fournit pas std::isnan
ni std::tr1::isnan
mais il fournit une fonction d'extension définie comme _isnan()
qui est disponible depuis Visual C++ 6.0
Sur XCode, il y a encore plus de plaisir. Comme mentionné, GCC 4+ définit std::isnan
. Pour les anciennes versions du compilateur et la bibliothèque forme XCode, il semble (ici est discussion pertinente ), je n'ai pas eu l'occasion de vérifier moi-même) deux fonctions sont définies, __inline_isnand()
sur Intel et __isnand()
sur Power PC.
Tout le monde veut ces fonctions comme isNan ou isInfinity. Pourquoi les responsables n'incluent-ils pas tout simplement dans leurs standards ????. - Je vais essayer de trouver comment devenir responsable et voter pour cela. Sérieusement.
Depuis que cette question a été posée, il y a eu quelques nouveaux développements : il faut savoir que std::isnan()
fait partie de C++11
Défini dans l'en-tête <cmath>
bool isnan( float arg ); (since C++11)
bool isnan( double arg ); (since C++11)
bool isnan( long double arg ); (since C++11)
Détermine si le nombre à virgule flottante donné arg n'est pas un nombre ( NaN
).
Paramètres
arg
: valeur à virgule flottante
Valeur de retour
true
si arg est NaN
, false
sinon
Référence
http://en.cppreference.com/w/cpp/numeric/math/isnan
Veuillez noter que ceci est incompatible avec -fast-math si vous utilisez g++, voir ci-dessous pour d'autres suggestions.
Pour C99, en C, ceci est implémenté comme une macro isnan(c)
qui renvoie une valeur int. Le type de x
doit être un flottant, un double ou un double long.
Les différents vendeurs peuvent inclure ou non une fonction isnan()
.
Le moyen supposé portable de vérifier NaN
est d'utiliser la propriété IEEE 754 qui NaN
n'est pas égal à lui-même : c'est-à-dire que x == x
sera faux pour x
être NaN
.
Cependant, la dernière option peut ne pas fonctionner avec tous les compilateurs et certains paramètres (en particulier les paramètres d'optimisation), donc en dernier recours, vous pouvez toujours vérifier le schéma binaire ...
Mérite définitivement d'être la réponse acceptée et mérite plus de votes positifs. Merci pour le conseil
1 std::isnan
est toujours une mauvaise recommandation en février 2017, car il ne fonctionne pas avec l'optimisation en virgule flottante de g++.
@Cheersandhth.-Alf : cette option est-elle conforme aux normes IEEE ? La réponse a été modifiée
Il existe également un bibliothèque d'en-tête seulement présents dans Boost qui ont des outils soignés pour traiter les types de données en virgule flottante.
#include <boost/math/special_functions/fpclassify.hpp>
Vous bénéficiez des fonctions suivantes :
template <class T> bool isfinite(T z);
template <class T> bool isinf(T t);
template <class T> bool isnan(T t);
template <class T> bool isnormal(T t);
Si vous avez le temps, jetez un coup d'œil à la boîte à outils Math de Boost, qui contient de nombreux outils utiles et qui se développe rapidement.
De même, lorsque vous traitez des points flottants et non flottants, il peut être judicieux de consulter l'outil de gestion des points. Conversions numériques .
Il existe trois méthodes "officielles" : posix isnan
macro , c++0x isnan
modèle de fonction ou visual c++ _isnan
función .
Malheureusement, il n'est pas très pratique de détecter laquelle de ces options utiliser.
Et malheureusement, il n'existe aucun moyen fiable de détecter si vous avez une représentation IEEE 754 avec des NaN. La bibliothèque standard offre un tel moyen officiel ( numeric_limits<double>::is_iec559
). Mais en pratique, les compilateurs tels que g++ gâchent tout.
En théorie, on pourrait utiliser simplement x != x
mais les compilateurs tels que g++ et visual c++ gâchent tout.
Donc, à la fin, testez pour le spécifique Modèles binaires NaN en supposant (et, espérons-le, en imposant, à un moment donné !) une représentation particulière telle que l'IEEE 754.
EDITAR pour illustrer le fait que les compilateurs tels que g++ font tout foirer, considérez les exemples suivants
#include <limits>
#include <assert.h>
void foo( double a, double b )
{
assert( a != b );
}
int main()
{
typedef std::numeric_limits<double> Info;
double const nan1 = Info::quiet_NaN();
double const nan2 = Info::quiet_NaN();
foo( nan1, nan2 );
}
Compilation avec g++ (TDM-2 mingw32) 4.4.1 :
C:\\test> type "C:\\Program Files\\@commands\\gnuc.bat"
@rem -finput-charset=windows-1252
@g++ -O -pedantic -std=c++98 -Wall -Wwrite-strings %\* -Wno-long-long
C:\\test> gnuc x.cpp
C:\\test> a && echo works... || echo !failed
works...
C:\\test> gnuc x.cpp --fast-math
C:\\test> a && echo works... || echo !failed
Assertion failed: a != b, file x.cpp, line 6
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
!failed
C:\\test> \_
@Alf : Votre exemple fonctionne comme prévu pour moi sur Mac OS X et Linux avec différentes versions de g++ entre 4.0 et 4.5. La documentation de l -ffast-math
indique explicitement qu'elle peut entraîner une sortie incorrecte pour les programmes qui dépendent d'une implémentation exacte des règles/spécifications IEEE ou ISO pour les fonctions mathématiques. Sans cette option, l'utilisation de x != x
est un moyen parfaitement valide et portable de tester les NaN.
@Adam : Ce que vous ne comprenez pas, c'est que la norme C++ ne requiert pas de représentation IEEE ou de calcul pour les flottants. D'après la page de manuel, gcc -ffast-math
est toujours une implémentation C++ conforme (enfin, en supposant qu'il obtienne numeric_limits::is_iec559
C'est vrai, bien qu'Alf suggère ci-dessus que ce n'est pas le cas) : Le code C++ qui s'appuie sur IEEE est no C++ portable et n'a pas le droit d'attendre des implémentations qu'elles le fournissent.
Et Alf a raison, un test rapide sur gcc 4.3.4 et is_iec559
est vrai avec -ffast-math
. Le problème ici est que la documentation de GCC pour -ffast-math
disent seulement qu'il est non-IEEE/ISO pour les fonctions mathématiques, alors qu'ils devrait dire qu'il n'est pas C++, parce que sa mise en œuvre de numeric_limits
est borked. Je suppose que GCC n'est pas toujours en mesure de dire, au moment où le modèle est défini, si l'éventuel backend a effectivement des flottants conformes, et donc n'essaie même pas. IIRC il y a des problèmes similaires dans la liste des bogues en suspens pour la conformité de GCC à C99.
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.
2 votes
Je ne suis pas sûr qu'on puisse le faire de manière portative. Qui a dit que le C++ nécessite IEEE754 ?
0 votes
Voir aussi : Comment faire une fonction isnan/isinf portable ?
2 votes
Il faut savoir qu'une once de prévention vaut mieux qu'une livre de remèdes. En d'autres termes, empêchant 0.f/0.f d'être jamais exécuté est bien meilleure que la vérification rétroactive de
nan
dans votre code.nan
peut être terriblement destructeur pour votre programme, si on le laisse proliférer, il peut introduire des bogues difficiles à trouver. Ceci est dû au fait quenan
est toxique, (5*nan
=nan
),nan
n'est pas égal à quelque chose (nan
!=nan
),nan
pas plus grand que quoi que ce soit (nan
!> 0),nan
n'est pas inférieur à quoi que ce soit (nan
!< 0).1 votes
@bobobo : C'est une fonctionnalité, permettant une vérification centralisée des erreurs. Tout comme les exceptions par rapport aux valeurs de retour.
2 votes
Pourquoi <cmath> n'a pas isnan() ? C'est dans std: :