float f = (float)'a';
if(f < 0){
}
else if(f == 0){
}
else if(f > 0){
}
else{
printf("NaN\n");
}
f
ne sera pas supérieur/égal/inférieur à 0
s'il s'agit d'une NaN
.
Mais comment produire un tel f
en premier lieu?
J'ai essayé différentes méthodes pour produire une variable NaN
, mais aucune ne fonctionne.
En utilisant des nombres à virgule flottante, 0.0 / 0.0
n'est pas une erreur de "division par zéro"; il en résulte NaN
.
Ce programme C imprime -nan
:
#include <stdio.h>
int main()
{
float x = 0.0 / 0.0;
printf("%f\n", x);
return 0;
}
En termes de l'apparence de NaN
sur l'ordinateur, deux nombres "non valides" sont réservés à "signalisation" et à NaN "silencieux" (semblables aux deux nombres non valides réservés aux infinis positif et négatif). Le entrée Wikipedia contient plus de détails sur la façon dont NaN est représenté sous forme de nombre à virgule flottante IEE.
Pour produire un nan, il y a plusieurs façons:
1) le générer manuellement (lisez ieee754
pour configurer correctement les bits)
2) utiliser une macro. GCC expose une macro NAN
. C'est défini dans math.h
La manière générale de vérifier un nan est de vérifier if (f == f)
(ce qui devrait échouer pour les valeurs nan)
Pour nan, les bits d'exposant dans la représentation float doivent tous être mis à 1 (float consiste en un bit signé, un ensemble de bits d'exposant et un ensemble de bits de mantisse)
Dans le manuel GNU de GCC, math.h
définit des macros permettant de définir explicitement une variable sur infini ou sur NaN. Comme il s’agit d’une partie de C99, vous pouvez utiliser les macros suivantes avec d’autres compilateurs compatibles C99.
- Macro: float INFINITY Expression représentant l'infini positif. Il est égal à la valeur produite par des opérations mathématiques telles que 1.0/0.0. -INFINITY représente l'infini négatif.
Vous pouvez tester si une valeur à virgule flottante est infinie en la comparant à cette macro. Cependant, ce n'est pas recommandé. vous devriez plutôt utiliser la macro isfinite. Voir Classes en virgule flottante.
Cette macro a été introduite dans la norme ISO C99.
- Macro: float NAN Expression représentant une valeur qui n'est «pas un nombre». Cette macro est une extension GNU, disponible uniquement sur les machines prenant en charge la valeur «not a number», c'est-à-dire sur toutes les machines prenant en charge le point flottant IEEE.
Vous pouvez utiliser ‘#ifdef NAN’ pour vérifier si la machine prend en charge NaN. (Bien entendu, vous devez faire en sorte que les extensions GNU soient visibles, par exemple en définissant _GNU_SOURCE, puis vous devez inclure math.h.)
pour plus d'informations, voir ici: http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html
Vous pouvez utiliser la macro NAN
ou simplement l’une des fonctions nan/nanf
pour attribuer une valeur nan à une variable.
pour vérifier si vous avez affaire à une valeur nan, vous pouvez utiliser isnan()
. En voici un exemple:
#include <stdio.h>
#include <math.h>
int main(void) {
float a = NAN;//using the macro in math.h
float f = nanf("");//using the function version
double d = nan("");//same as above but for doubles!
printf("a = %f\nf = %f\nd = %f\n",a,f,d);
if(isnan(a))
puts("a is a not a number!(NAN)\n");
return 0;
}
L'exécution de l'extrait de code ci-dessus vous donnera cette sortie:
a = nan
f = nan
d = nan
a is a not a number!(NAN)
Exécutez le code vous-même: http://ideone.com/WWZBl8
en savoir plus: http://www.cplusplus.com/reference/cmath/NAN/
Pour les implémentations C hébergées, vous pouvez créer un #include <math.h>
et utiliser la macro NAN
si elle est définie. Par exemple, avec GCC, il est implémenté par un élément intégré: (__builtin_nanf (""))
.
Pour les implémentations C autonomes (sur lesquelles l'en-tête <math.h>
peut ne pas être disponible) ou lorsque la macro NAN
n'est pas définie (ce qui peut arriver même si NaN peut être pris en charge), il est possible de générer un NaN avec une opération en virgule flottante telle que 0.0 / 0.0
. Cependant, il peut y avoir plusieurs problèmes avec cela.
Premièrement, une telle opération génère également une exception, avec une interruption possible sur certaines implémentations en C. On peut s’assurer qu’il est calculé au moment de la compilation avec:
static double my_nan = 0.0 / 0.0;
Un autre problème est que Microsoft Visual C++ (au moins certaines versions) tente d’évaluer 0.0 / 0.0
au moment de la compilation (même lorsque cette expression se trouve à un endroit arbitraire du code) et se plaint de sa validité. Donc, la solution ici est l'inverse: assurez-vous que le compilateur ne l'évaluera pas au moment de la compilation, en faisant:
static double zero = 0.0;
puis utilisez zero / zero
. Puisque ces solutions sont en conflit, on peut tester le compilateur avec des directives de préprocesseur (#if
...) sur macros spécifiques .
On peut également choisir une solution basée sur le codage NaN, mais il existe également des problèmes de portabilité. Premièrement, la norme IEEE 754 ne définit pas complètement le codage d'un NaN, en particulier la façon de distinguer les NaN silencieux et les signaux de signalisation (et le matériel diffère dans la pratique); les NaN de signalisation produiront un comportement indéfini. De plus, la norme IEEE 754 ne définit pas comment la chaîne de bits est représentée en mémoire, c’est-à-dire que l’endianité peut avoir besoin d’être détectée. Si ces problèmes sont résolus, une union ou un tableau de unsigned char
avec une conversion de pointeur suffit pour obtenir le type à virgule flottante. N'utilisez pas un entier avec un pointeur sur son adresse pour faire une frappe, car cela enfreindrait les règles d'aliasing C.
Cela fonctionne aussi pour les constantes (0/0 donnera une erreur de compilation sur vs):
const unsigned maxU = ~0;
const float qNan = *((float*)&maxU);
nan est produit lorsque nous programmons une valeur telle que 0.0/0.0, comme l'a dit @Dan Cecile OR sqrt (-1).
Le programme suivant produira un NaN. La deuxième déclaration se traduira par un NaN.
#include <stdio.h>
#include <tchar.h>
#include "math.h"
int _tmain(int argc, _TCHAR* argv[])
{
double dSQRTValue = sqrt( -1.00 );
double dResult = -dSQRTValue; // This statement will result in a NaN.
printf( "\n %lf", dResult );
return 0;
}
Ce qui suit sera la sortie du programme.
1. # QNAN0