IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Calcul -> NAN en C++


Sujet :

C++

  1. #1
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut Calcul -> NAN en C++
    Bonjour à tous!

    Question de la mort qui tue: comment savoir que le résultat d'une opération est invalide?
    Je m'explique: si par exemple je fais une division par 0, comment je peux savoir que le contenu de ma variable n'est pas valide (équivalent NAN sur Excel par exemple)?

    Contexte: j'ai récupéré une DLL qui fait des calculs. Il y a des fonctions exportées qui renvoient des résultats (double) en fonction des paramètres d'entrée. Sauf que la personne qui a fait cette DLL n'a pa prévu les cas de calculs ambigües (division par 0, ...). Résultat, dès que je formate le résultat à problème dans une chaîne de caractères, je me récupère un magnifique "1.#INF".

    Y-a-t'il moyen de le savoir avant de formater le texte et faire une recherche sur le caractère '#' par exemple? Est-ce que je peux le savoir rien qu'avec la variable de retour?

    Merci d'avance.
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  2. #2
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Une division par zéro produit un nombre tout à fait valide en C++, tu peux le tester avec std::numeric_limits< double >::infinity() par exemple.

    Pour tester NaN tu peux tester si un nombre est bien égal à lui-même (NaN est différent de lui-même).

    La représentation obtenue sous forme de chaîne de caractères avec les iostreams dépend de la plate-forme par contre...

    MAT.

  3. #3
    Membre expérimenté Avatar de BainE
    Inscrit en
    Mai 2004
    Messages
    1 327
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 1 327
    Points : 1 544
    Points
    1 544
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    Une division par zéro produit un nombre tout à fait valide en C++
    Ca plante une division par zero, en tout cas avec gcc et le compilo de visual 2005.
    "vaste programme"

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    399
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 399
    Points : 413
    Points
    413
    Par défaut
    a l'execution, a partir d'une variable, ca ne plante pas. Par contre j'ai remarqué que ca faisait ramer le code a fond (enfin je ne c pas si c'etait la division en elle meme ou les calcul avec l'infini résultants)
    SPARK
    Moteur de particule C++ opensource avec modules de rendu OpenGL, Irrlicht et SFML

  5. #5
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Citation Envoyé par BainE Voir le message
    Ca plante une division par zero, en tout cas avec gcc et le compilo de visual 2005.
    Hmm pas chez moi...

    Avec VC2005 ce test passe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    BOOST_AUTO_TEST_CASE( DivisionByZero )
    {
        static const float ZERO = 0.f;
        BOOST_CHECK_EQUAL( std::numeric_limits< float >::infinity(), 1.f / ZERO );
    }
    Avec g++ sous cygwin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <iostream>
     
    int main()
    {
      static const float ZERO = 0.f;
      if( std::numeric_limits< float >::infinity() == 1.f / ZERO )
        std::cout << "OK" << std::endl;
      return 0;
    }
    En faisant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $ g++ -Wall divide_by_zero.cpp
    divide_by_zero.cpp: In function `int main()':
    divide_by_zero.cpp:6: warning: division by zero in `1.0e+0f / 0.'
     
    $ ./a.exe
    OK
    Qu'est ce que tu entends exactement par "ça plante" ?

    MAT.

  6. #6
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Une division par un flottant nul ne 'plante' pas (n'émet pas d'exception si c'est ce que tu voulais dire), mais raise un flag.
    Une division par un entier nul, par contre, envoie une exception CPU.
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  7. #7
    Membre régulier

    Profil pro
    Étudiant
    Inscrit en
    Juin 2006
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2006
    Messages : 78
    Points : 105
    Points
    105
    Par défaut
    Citation Envoyé par Frifron Voir le message
    Par contre j'ai remarqué que ca faisait ramer le code a fond (enfin je ne c pas si c'etait la division en elle meme ou les calcul avec l'infini résultants)
    Oui le code devient très lent, mais pour aucune des deux raisons citées. Quand tu effectues un calcul avec un NaN (je ne suis pas certain si c'est au moment où tu l'obtiens ou au moment où tu l'utilise), le processeur émet une exception matériel, qui émet alors une interruption et fait donc passer le processeur en mode noyau (tout en branchant sur l'IRQ enregistrée, elle-même rendant généralement la main au noyau).
    Lorsque tu obtiens des NaN, imagine que ton processus se met à rendre la main au noyau a chaque calcul...

    Il y a quelques patchs pour le noyau Linux qui changent l'IRQ qui gère ce problème afin de diminuer la perte de vitesse lors de calculs très intensifs, mais ça ne fait pas des miracles... Sans compter qu'un NaN se propage... Vite.

    Citation Envoyé par nicroman Voir le message
    Une division par un flottant nul ne 'plante' pas (n'émet pas d'exception si c'est ce que tu voulais dire), mais raise un flag.
    Une division par un entier nul, par contre, envoie une exception CPU.
    Si c'est vraiment le cas, ce doit être paramétrable au lancement du noyau. Sur tous les systèmes que j'ai utilisés, ce n'est pas le cas, et des NaN avec des flottant y émettent bien des interruptions matérielles.
    "The worst errors I've ever seen do not came from no knowledge, but from having just the the right amount of it, too small to really understand what you're doing, but enough to think you did. That amount of knowledge, is evil."

  8. #8
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut
    Merci à tous pour vos réponses.
    Après divers essais, je peux vous dire:
    Citation Envoyé par Mat007
    Pour tester NaN tu peux tester si un nombre est bien égal à lui-même (NaN est différent de lui-même).
    Je n'ai pas pu vérifier, mon retour étant un double (et le == n'est pas valable sur un double ). Peut être sur un int?
    Citation Envoyé par Mat007
    Citation Envoyé par BainE
    Ca plante une division par zero, en tout cas avec gcc et le compilo de visual 2005.
    Hmm pas chez moi...
    Oui et non (j'utilise VS). Une division explicite dans le code t'attireras les foudres du compilateur:
    error C2124: division ou modulo par zéro
    Une division par 0 "cachée" n'empêchera pas la compilation, te produiras éventuellement un warning (pas systématique), mais plantera à l'exécution ("XXXX a rencontré un problème et doit fermer....", je suis sous XP):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int iNum = 1;
    int iDen = 0;
    int iQuo = iNum/iDen;
    warning C4723: division potentielle par 0
    Sauf que dans mon cas, c'est-à-dire la division dans une DLL annexe et le résultat renvoyé dans le programme principal, le plantage n'intervient pas, et c'est cet espèce de NaN qui m'est renvoyé.
    Citation Envoyé par Mat007
    Une division par zéro produit un nombre tout à fait valide en C++, tu peux le tester avec std::numeric_limits< double >::infinity() par exemple.
    Effectivement, j'ai vérifié et je vais faire comme cela .
    Merci à tous!
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  9. #9
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par spoutspout Voir le message
    Après divers essais, je peux vous dire:Je n'ai pas pu vérifier, mon retour étant un double (et le == n'est pas valable sur un double ).
    Bien sur que si il est valable. NAN est garanti être le seul double non égal à lui même. Il n'est pas garanti que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 == 1
    Mais il est garanti que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 == 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  10. #10
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut
    Mais ce n'est pas applicable à un retour de fonction car je ne peux pas deviner ce qui me sera renvoyé, et donc par rapport à quoi il me faut tester ce retour (mon but est juste de détecter si la valeur est valide, pas si elle est égale à quelque chose).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    double dMyVar = MyFonction(...);
     
    if(dMyVar == dMyVar)
        cout << "Valide";
    else
        cout << "Pas valide";
    Si ma fonction me renvoie "1.#INF0000..." (sous Visual, une fois formaté en texte) c'est à dire NaN, c'est le "Valide" qui est affiché, ce qui est faux. Donc vérifier un double en testant s'il est égal à lui-même ne fonctionne pas.
    Ou alors je n'ai pas compris ce que vous m'avez suggéré .

    D'une manière générale, je ne fais jamais du "==" avec les double car ça pose quand même souvent problème. Par exemple, dans le test suivant, c'est "pas égal" qui est affiché:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    double dVal1 = 0.1 + 0.1 + 0.1 + 0.1 + 0.1; // = 0.5
    double dVal2 = 1.0 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1; // = 0.5 aussi
     
    if(dVal1 == dVal2)
        cout << "égal";
    else
        cout << "pas égal";
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  11. #11
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Infinity (INF) et Not-A-Number (NAN) ne sont pas la même chose.
    L'infini est un nombre, et c'est ce que tu obtiens dans ton cas lors d'une division par zéro, et tu le testes avec == std::numeric_limits< double >::infinity() (ou avec !=).

    MAT.

  12. #12
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut
    OK, j'avais sûrement mal ciblé et/ou expliqué mon problème.
    Merci
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  13. #13
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    La représentation obtenue sous forme de chaîne de caractères avec les iostreams dépend de la plate-forme par contre...
    Du coup, est-ce le cas également pour la représentation d'infini?
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  14. #14
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Citation Envoyé par spoutspout Voir le message
    Du coup, est-ce le cas également pour la représentation d'infini?
    Oui.

    Par exemple avec g++ sous cygwin on aura inf alors que msvc donnera 1.#INF.

    MAT.

  15. #15
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut
    Je permets de remonter ce topic, car j'ai un autre problème du même genre. Le debuggeur de Visual me renvoie non plus 1.#INF, mais 1.#IND. Ceci apparait quand j'effectue un 0/0.
    J'ai recherché du côté des std::numeric_limits, mais je n'ai rien trouvé correspondant au IND (comme infinity() pour INF).
    J'ai deux questions:
    • Qu'est-ce que "IND"? Indéfini? Indivisible?
    • Comment faire le même genre de test que précédemment pour détecter le IND?
    Merci d'avance.
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    399
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 399
    Points : 413
    Points
    413
    Par défaut
    J'imagine que c'est INDEFINITE. 0 / 0 a un résultat non défini. Ca doit être plus ou moins équivalent a un NaN.
    SPARK
    Moteur de particule C++ opensource avec modules de rendu OpenGL, Irrlicht et SFML

  17. #17
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut
    Citation Envoyé par Frifron Voir le message
    J'imagine que c'est INDEFINITE. 0 / 0 a un résultat non défini. Ca doit être plus ou moins équivalent a un NaN.
    Donc détectable avec un quiet_NaN() ?
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  18. #18
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par spoutspout Voir le message
    Donc détectable avec un quiet_NaN() ?
    Comment?

    La seule maniere, c'est de voir s'il est egal a lui-meme. Si ce n'est pas le cas, tu as un NaN. En passant, il y a pas mal de NaN differents, en theorie ont pourrait initialiser toutes les variables float/doubles avec un et voir a la fin si on a du calcul qui fait intervenir des variables non initialisees et trouver une d'entre elles -- les operations prenant un ou plusieurs NaN en entree doivent retourner un de ceux-ci comme resultat.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  19. #19
    Membre éprouvé
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Points : 1 067
    Points
    1 067
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Comment?
    Ben de la même manière que pour le 1.#INF:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    double dProut = 51/0; // forcément ça compilera pas, mais c'est pour illustrer
     
    if(dProut == std::numeric_limits<double>::infinity())
        std::cout << dProut << std::endl;
    Faudrait que j'arrive à reprosuire ce 1.#IND pour tester quiet_NaN()... Je vais creuser ça
    "L'ordinateur obéit à vos ordres, pas à vos intentions." [Anonyme]

  20. #20
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par spoutspout Voir le message
    Ben de la même manière que pour le 1.#INF:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    double dProut = 51/0; // forcément ça compilera pas, mais c'est pour illustrer
     
    if(dProut == std::numeric_limits<double>::infinity())
        std::cout << dProut << std::endl;
    Faudrait que j'arrive à reprosuire ce 1.#IND pour tester quiet_NaN()... Je vais creuser ça
    Pour la troisieme fois dans ce fil, les NaN ne sont pas egaux a eux-memes.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. résultat de calcul NaN
    Par insomai dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 12/08/2011, 18h20
  2. calcul: pourquoi NAN
    Par nsanabi dans le forum Langage
    Réponses: 11
    Dernier message: 25/10/2010, 13h14
  3. [Débutant] Calculer en excluant NaN et valeur 0
    Par kariboubou dans le forum MATLAB
    Réponses: 4
    Dernier message: 31/05/2010, 17h18
  4. Valeur de retour d'un petit calcul "NaN"
    Par lodan dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 09/01/2007, 21h10
  5. [NaN] Calcul d'une régression linéaire
    Par GLDavid dans le forum Langage
    Réponses: 1
    Dernier message: 24/10/2006, 12h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo