2012-07-02 19 views
8

¿Qué es 1.#INF y por qué el fundido a float o double previene una división por 0 de bloqueo?
Además, ¿hay alguna idea de cómo evitar la división por 0? (Como cualquier macro o plantilla)?Dividir por cero prevención

int nQuota = 0; 

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

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

si uso su lugar:

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

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

wow interesting. Esperando una respuesta. –

+0

esto podría ser interesante para usted: http://blog.regehr.org/archives/721 – cppanda

Respuesta

12

1.#INF es infinito positivo. Lo obtendrá cuando divida un flotante positivo entre cero (si divide el cero flotante en cero, el resultado será "no un número").

Por otro lado, si divide un entero por cero, el programa se bloqueará.

El motivo float fZero = 2/nQuota; se bloquea porque ambos operandos del operador / son enteros, por lo que la división se realiza en enteros. No importa que guarde el resultado en un flotador; C++ no tiene noción de tipaje objetivo.

Por qué el infinito molde positivo a un número entero es el número entero más pequeño, que no tienen ni idea.

+0

¿qué pasa con -2147483648? –

+1

-2147483648 es 1. # INF lanzado a un número entero. –

+3

La especificación C no parece especificar el resultado de convertir 'NaN' o un valor flotante infinito en un entero. "Si el valor de flotación es infinito o NaN o si la parte integral del valor flotante excede del rango del tipo entero, entonces se levanta la excepción de punto flotante 'inválido' y el valor resultante no se especifica". – mkb

1

Por lo general, asegúrese de no dividir por cero. El código de abajo no es particularmente útil a menos nQuota tiene un valor legítimo pero impide accidentes

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

Un poco simple, pero es como un amuleto. –

3

Wwhy usando (float) o (doble) impide una división por 0 de estrellarse?

No necesariamente. El estándar es increíble de repuesto cuando se trata de punto flotante. La mayoría de los sistemas utilizan el estándar de punto flotante IEEE hoy en día, y eso dice que la acción predeterminada para la división por cero es devolver ± infinito en lugar de bloquearse. Puede hacer que se bloquee habilitando las excepciones apropiadas de punto flotante.

Nota bien: La única cosa que el modelo de excepción de coma flotante y el modelo de excepciones de C++ tienen en común es la palabra "excepción". En cada máquina en la que trabajo, una excepción de punto flotante no arroja una excepción de C++.

¿Alguna idea de cómo evitar la división por 0?

  1. Respuesta simple: No lo haga.
    Este es uno de esos "Doctor, doctor, duele cuando hago esto!" tipos de situaciones. ¡Entonces no lo hagas!

  2. Asegúrese de que el divisor no sea cero.
    Realice verificaciones de cordura en los divisores que son entradas del usuario. Siempre filtra tus entradas de usuario por cordura. Un valor de entrada de usuario de cero cuando se supone que el número es de millones provocará todo tipo de estragos además del desbordamiento. Haga verificaciones de cordura en valores intermedios.

  3. Habilitar excepciones de punto flotante.
    Hacer el comportamiento predeterminado para permitir errores (y estos son casi siempre errores) para pasar sin marcar fue en mi humilde opinión un gran error por parte del comité de estándares.Use el valor por defecto y esos infinitos y no-números eventualmente convertirán todo en un Inf o un NaN.
    El valor predeterminado debería haber sido detener los errores de coma flotante en sus pistas, con una opción para permitir que cosas como 1.0/0.0 y 0.0/0.0 tengan lugar. Ese no es el caso, entonces tienes que habilitar esas trampas. Haga eso y con frecuencia puede encontrar la causa del problema en poco tiempo.

  4. Escribir división personalizada, multiplicación personalizada, raíz cuadrada personalizada, seno personalizado, ... funciones.
    Desafortunadamente esta es la ruta que muchos sistemas de software de seguridad crítica deben tomar. Es un dolor real. La opción n. ° 1 está fuera porque es solo una ilusión. La opción n. ° 3 está desactivada porque no se permite que el sistema se cuelgue. La opción n. ° 2 sigue siendo una buena idea, pero no siempre funciona porque los datos incorrectos siempre tienen una forma de entrar furtivamente. Es la ley de Murphy.

Por cierto, el problema es un poco peor que la división por cero. 10 /10 -200 también se desbordará.