Dans mes programmes, l'infini se produit généralement lorsqu'une valeur est divisée par zéro. Je deviens indéterminé quand je divise zéro par zéro. Comment vérifier les valeurs infinies et indéterminées en C++?
En C++, l'infini est représenté par 1. # INF. Indéterminé est représenté par -1. # IND. Le problème est de savoir comment tester si une variable est infinie ou indéterminée. Vérifier l'infini est relativement simple: vous trouvez la définition de l'infini dans votre C++ particulier. Pour mon cas (VS2003), c'est std :: numeric_limits :: infinity (). Vous devez inclure des "limites" pour pouvoir l'utiliser. Vous pouvez affecter cette valeur infinie à une variable et la comparer à une valeur afin de vérifier si cette valeur est infinie.
Indéterminé est un peu délicat, car vous ne pouvez pas comparer une valeur indéterminée à une autre valeur. Toute comparaison retourne false. Vous pouvez utiliser cette propriété pour détecter une valeur indéterminée en la comparant à elle-même. Disons que vous avez une double variable appelée aVal. Dans des conditions normales, aVal! = AVal renvoie false. Mais si la valeur est indéterminée, aIndVal! = AIndVal renvoie true. Cette situation étrange n’est pas présente pour les valeurs infinies, c’est-à-dire aInfVal! = AInfVal renvoie toujours false.
Voici deux fonctions qui peuvent être utilisées pour vérifier les valeurs indéterminées et infinies:
#include "limits.h"
#include "math.h"
bool isIndeterminate(const double pV)
{
return (pV != pV);
}
bool isInfinite(const double pV)
{
return (fabs(pV) == std::numeric_limits::infinity())
}
Existe-t-il de meilleurs moyens de procéder à ces vérifications?
Pour Visual Studio, je voudrais utiliser _isnan
et _finite
, ou peut-être _fpclass
.
Mais si vous avez accès à une bibliothèque et à un compilateur standard compatibles C++ 11, vous pouvez utiliser std::isnan
et std::isinf
.
Bien que C++ 03 ne fournisse pas les isnan et isinf macros de C99, C++ 11 les standardise en les fournissant comme fonctions . Si vous pouvez utiliser C++ 11, au lieu de C++ 03 strict, il s'agira d'options plus propres, en évitant les macros, les fonctions intégrées au compilateur } et dépendantes de la plate-forme.
std::isfinite
de C++ 11 renvoie true
pour toutes les valeurs sauf inf
et nan
; donc !isfinite
devrait vérifier les valeurs infinies et indéterminées d’un seul coup.
Vous pouvez également les utiliser comme une solution strictement C++ uniquement. Ils n'offrent pas vraiment plus que la solution de l'OP, sauf une sécurité accrue grâce à l'utilisation de caractères de type et peut-être la plus petite augmentation de vitesse dans le cas de is_inf
.
template <bool> struct static_assert;
template <> struct static_assert<true> { };
template<typename T>
inline bool is_NaN(T const& x) {
static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_quiet_NaN>));
return std::numeric_limits<T>::has_quiet_NaN and (x != x);
}
template <typename T>
inline bool is_inf(T const& x) {
static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_infinity>));
return x == std::numeric_limits<T>::infinity() or x == -std::numeric_limits<T>::infinity();
}
(méfiez-vous de l'auto-fabrication static_assert
)
Bien que cela ne fasse pas strictement partie de C++ 03, si votre compilateur fournit certaines des nouvelles fonctionnalités C99 du fichier d’en-tête standard <math.h>, vous pouvez accéder aux "macros de type fonction" suivantes: isfinite
, isinf
isnan
. Si tel est le cas, il s’agit du moyen le plus simple et le plus sûr d’effectuer ces vérifications.
Il y a isfinite
de C99 ou POSIX ou quelque chose que je pense.
Une façon astucieuse de le faire est de tester x-x == 0
; Si x
est infini ou NaN, alors x-x
est NaN et la comparaison échoue. Si x
est fini, alors x-x
est 0
et la comparaison aboutit. Je vous conseillerais toutefois d'utiliser isfinite
ou de regrouper ce test dans une fonction/macro appelée quelque chose comme isfinite
afin de pouvoir vous en débarrasser le moment venu.
if (x!=x) ... then x is nan
if (x>0 && x/x != x/x) ... then x is +inf
if (x<0 && x/x != x/x) ... then x is -inf
cela pourrait aussi fonctionner (mais implique l'appel à exp () et le test de l'égalité des doublons):
if (exp(-x)==0.) ... then x is inf
if (exp(x)==0.) ... then x is -inf