37 votes

comment créer une fonction portable isnan / isinf

J'ai été en utilisant isinf, isnan fonctionne sur les plates-formes Linux qui a parfaitement fonctionné. Mais cela ne fonctionne pas sur OS-X, j'ai donc décidé d'utiliser std::isinf std::isnan qui fonctionne à la fois sur Linux et OS-X.

Mais le compilateur Intel ne veut pas le reconnaître, et je suppose que c'est un bug du compilateur intel selon http://software.intel.com/en-us/forums/showthread.php?t=64188

Alors maintenant, je veux juste éviter les tracas et de définir ma propre isinf, isnan mise en œuvre.

Personne ne sait comment cela pourrait être fait?

edit:

J'ai fait cela dans mon code source pour faire isinf/isnan de travail

#include <iostream>
#include <cmath>

#ifdef __INTEL_COMPILER
#include <mathimf.h>
#endif

int isnan_local(double x) { 
#ifdef __INTEL_COMPILER
  return isnan(x);
#else
  return std::isnan(x);
#endif
}

int isinf_local(double x) { 
#ifdef __INTEL_COMPILER
  return isinf(x);
#else
  return std::isinf(x);
#endif
}


int myChk(double a){
  std::cerr<<"val is: "<<a <<"\t";
  if(isnan_local(a))
    std::cerr<<"program says isnan";
  if(isinf_local(a))
    std::cerr<<"program says isinf";
  std::cerr<<"\n";
  return 0;
}

int main(){
  double a = 0;
  myChk(a);
  myChk(log(a));
  myChk(-log(a));
  myChk(0/log(a));
  myChk(log(a)/log(a));

  return 0;
}

25voto

math Points 2127

Vous pouvez également utiliser le boost pour cette tâche:

 #include <boost/math/special_functions/fpclassify.hpp> // isnan

if( boost::math::isnan( ... ) .... )
 

21voto

Johann Hibschman Points 602

Je n'ai pas essayé ça, mais je pense

 int isnan(double x) { return x != x; }
int isinf(double x) { return !isnan(x) && isnan(x - x); }
 

travaillerait. Il semble qu'il devrait y avoir un meilleur moyen pour isinf, mais cela devrait fonctionner.

7voto

Contango Points 7976

Cela fonctionne sous Visual Studio 2008:

 #include <math.h>
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#define fpu_error(x) (isinf(x) || isnan(x))
 

Pour des raisons de sécurité, je recommande d'utiliser fpu_error (). Je crois que certains nombres sont récupérés avec isnan (), et certains avec isinf (), et vous avez besoin des deux pour être en sécurité.

Voici un code de test:

 double zero=0;
double infinite=1/zero;
double proper_number=4;
printf("isinf(infinite)=%d.\n",isinf(infinite));
printf("isinf(proper_number)=%d.\n",isinf(proper_number));
printf("isnan(infinite)=%d.\n",isnan(infinite));
printf("isnan(proper_number)=%d.\n",isnan(proper_number));

double num=-4;
double neg_square_root=sqrt(num);
printf("isinf(neg_square_root)=%d.\n",isinf(neg_square_root));
printf("isinf(proper_number)=%d.\n",isinf(proper_number));
printf("isnan(neg_square_root)=%d.\n",isnan(neg_square_root));
printf("isnan(proper_number)=%d.\n",isnan(proper_number));
 

Voici la sortie:

 isinf(infinite)=1.
isinf(proper_number)=0.
isnan(infinite)=0.
isnan(proper_number)=0.
isinf(neg_square_root)=1.
isinf(proper_number)=0.
isnan(neg_square_root)=1.
isnan(proper_number)=0.
 

7voto

bobobobo Points 17477

isnan est une partie de C++11, inclus dans GCC++ je crois, et Apple LLVM.

Maintenant MSVC++ a un _isnan fonction <float.h>.

Approprié #defines et #includes doit apporter une solution adaptée.

Cependant, je recommande de prévenir nan de se produire, au lieu de nan détection.

6voto

paxdiablo Points 341644

Ainsi, idéalement, vous deviez attendre Intel corrige le bug ou fournit une solution de contournement :-)

Mais si vous voulez détecter NaN et Inf de IEEE754 des valeurs, de la carte en un nombre entier (32 ou 64 bits en fonction de si c'est simple ou double précision) et vérifier si les bits d'exposant sont tous des 1. Cela indique que ces deux cas.

Vous pouvez faire la distinction entre NaN et Inf en vérifiant le bit de poids fort de la mantisse. Si c'est 1, c'est NaN sinon, Inf.

+/-Inf est dictée par le bit de signe.

Pour la simple précision (32 bits de valeurs), le signe de la haute-bit (b31), l'exposant est le suivant huit bits (plus de 23 bits de mantisse). Pour la double précision, le signe est toujours le haut afin de peu, mais l'exposant est onze bits (plus de 52 bits pour la mantisse).

Wikipédia a tous les détails sanglants.

Le code suivant montre comment utiliser l'encodage des œuvres.

#include <stdio.h>

static void decode (char *s, double x) {
    long y = *(((long*)(&x))+1);

    printf("%08x ",y);
    if ((y & 0x7ff80000L) == 0x7ff80000L) {
        printf ("NaN  (%s)\n", s);
        return;
    }
    if ((y & 0xfff10000L) == 0x7ff00000L) {
        printf ("+Inf (%s)\n", s);
        return;
    }
    if ((y & 0xfff10000L) == 0xfff00000L) {
        printf ("-Inf (%s)\n", s);
        return;
    }
    printf ("%e (%s)\n", x, s);
}

int main (int argc, char *argv[]) {
    double dvar;

    printf ("sizeof double = %d\n", sizeof(double));
    printf ("sizeof long   = %d\n", sizeof(long));

    dvar = 1.79e308; dvar = dvar * 10000;
    decode ("too big", dvar);

    dvar = -1.79e308; dvar = dvar * 10000;
    decode ("too big and negative", dvar);

    dvar = -1.0; dvar = sqrt(dvar);
    decode ("imaginary", dvar);

    dvar = -1.79e308;
    decode ("normal", dvar);

    return 0;
}

et c'sorties:

sizeof double = 8
sizeof long   = 4
7ff00000 +Inf (too big)
fff00000 -Inf (too big and negative)
fff80000 NaN  (imaginary)
ffefdcf1 -1.790000e+308 (normal)

Il suffit de garder à l'esprit que ce code (mais pas la méthode) dépend beaucoup de la taille de vos longs qui n'est pas trop portable. Mais, si vous avez à peu violon à obtenir de l'information, vous avez déjà saisi de ce territoire :-)

En aparté, j'ai toujours trouvé Harald Schmidt IEEE754 convertisseur très utile pour la virgule flottante analyse.

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