2012-07-02 4 views
8

Qu'est-ce que et pourquoi la diffusion vers un float ou double empêche une division de 0 de se bloquer?
En outre, toutes les grandes idées sur la façon d'empêcher la division par 0? (Comme toute macro ou modèle)?Diviser par zéro prévention

int nQuota = 0; 

int nZero = 3/nQuota; //crash 
cout << nZero << endl; 

float fZero = 2/nQuota; //crash 
cout << fZero << endl; 

si je l'utilise à la place:

int nZero = 3/(float)nQuota; 
cout << nZero << endl; 
//Output = -2147483648 

float fZero = 2/(float)nQuota; 
cout << fZero << endl; 
//Output = 1.#INF 
+2

wow intéressant. Dans l'attente d'une réponse. –

+0

cela pourrait être intéressant pour vous: http://blog.regehr.org/archives/721 – cppanda

Répondre

12

1.#INF est infini positif. Vous l'obtiendrez quand vous divisez un flottant positif par zéro (si vous divisez le zéro flottant lui-même par zéro, alors le résultat sera "pas un nombre"). Par contre, si vous divisez un nombre entier par zéro, le programme se bloquera.

La raison float fZero = 2/nQuota; se bloque parce que les deux opérandes de l'opérateur / sont des entiers, donc la division est effectuée sur des entiers. Peu importe que vous stockiez ensuite le résultat dans un flotteur; C++ n'a aucune notion de typage de cible.

Pourquoi l'infini positif converti en entier est le plus petit entier, je n'en ai aucune idée.

+0

qu'en est-il de -2147483648? –

+1

-2147483648 est 1. # INF cast en nombre entier. –

+3

La spécification C ne semble pas spécifier le résultat de la conversion de «NaN» ou d'une valeur flottante infinie en nombre entier. "Si la valeur fl ottante est infinie ou NaN ou si la partie intégrale de la valeur fl ottante dépasse la plage du type entier, alors l'exception de point flottant '' invalide '' est augmentée et la valeur résultante est non spéci fi ée." – mkb

1

Vous vérifiez généralement que vous ne divisez pas par zéro. Le code ci-dessous n'est pas particulièrement utile à moins nQuota a une valeur légitime, mais il ne prévenir les accidents

int nQuota = 0; 
int nZero = 0; 
float fZero = 0; 
if (nQuota) 
    nZero = 3/nQuota; 
cout << nZero << endl; 

if (nQuota) 
    fZero = 2/nQuota; 
cout << fZero << endl; 
+0

Kinda simple, mais c'est comme un charme. –

3

Wwhy en utilisant (float) ou (double) empêche une division par 0 de plantage?

Ce n'est pas obligatoire. La norme est incroyable quand il s'agit de virgule flottante. La plupart des systèmes utilisent la norme à virgule flottante IEEE de nos jours, et cela signifie que l'action par défaut pour la division par zéro est de renvoyer ± l'infini plutôt que le crash. Vous pouvez le faire planter en activant les exceptions à virgule flottante appropriées. Remarquez bien: La seule chose en commun entre le modèle d'exception à virgule flottante et le modèle d'exception C++ est le mot "exception". Sur chaque machine sur laquelle je travaille, une exception à virgule flottante ne génère pas d'exception C++.

En outre, les grandes idées de la façon de prévenir la division par 0?

  1. Réponse simple: Ne pas le faire.
    Ceci est l'un de ces "Docteur, docteur ça fait mal quand je fais ça!" sortes de situations. Alors ne le fais pas!

  2. Assurez-vous que le diviseur n'est pas zéro.
    Effectuez-vous des vérifications de cohérence sur les diviseurs qui sont des entrées d'utilisateur. Toujours filtrer vos entrées utilisateur pour la santé mentale. Une valeur d'entrée d'utilisateur de zéro lorsque le nombre est censé être dans les millions entraînera toutes sortes de dégâts en plus de débordement. Est-ce que sanity vérifie les valeurs intermédiaires.

  3. Activer les exceptions à virgule flottante.
    Faire le comportement par défaut pour permettre aux erreurs (et ce sont presque toujours des erreurs) de passer par un non-vérifié était à mon humble avis une grosse erreur de la part du comité des normes.Utilisez la valeur par défaut et ces infinis et non-a-nombres finiront par tout transformer en Inf ou en NaN.
    La valeur par défaut aurait dû être d'arrêter les erreurs à virgule flottante dans leurs pistes, avec une option pour permettre à des choses comme 1.0/0.0 et 0.0/0.0 d'avoir lieu. Ce n'est pas le cas, vous devez donc activer ces pièges. Faites cela et vous pouvez souvent trouver la cause du problème en peu de temps.

  4. Écrire des fonctions de division personnalisée, de multiplication personnalisée, de racine carrée personnalisée, de sinus personnalisé, etc.
    Ceci est malheureusement la voie que de nombreux systèmes logiciels critiques de sécurité doivent prendre. C'est une douleur royale. L'option n ° 1 est sortie parce que c'est juste un vœu pieux. L'option n ° 3 est désactivée car le système ne peut pas être autorisé à planter. L'option 2 est toujours une bonne idée, mais elle ne fonctionne pas toujours parce que les mauvaises données ont toujours un moyen de se faufiler. C'est la loi de Murphy.

BTW, le problème est un peu pire que la simple division par zéro. 10 /10 -200 débordera également.

Questions connexes