tutorial smart remix programador online español curso c++ c floating-point divide-by-zero

c++ - remix - smart contracts ethereum



¿Puede un valor flotante cercano a cero causar un error de división por cero? (5)

Todo el mundo sabe que no debes comparar flotadores directamente, sino usar una tolerancia:

float a,b; float epsilon = 1e-6f; bool equal = (fabs(a-b) < epsilon);

Me preguntaba si lo mismo se aplica a la comparación de un valor a cero antes de usarlo en la división.

float a, b; if (a != 0.0f) b = 1/a; // oops?

¿También necesito comparar con épsilon en este caso?


¿También necesito comparar con épsilon en este caso?

Nunca recibirá un error de división por cero, ya que 0.0f se representa exactamente en un flotante IEEE .

Dicho esto, es posible que aún desee usar algo de tolerancia, aunque esto depende completamente de su aplicación. Si el valor "cero" es el resultado de otras operaciones matemáticas, es posible obtener un número muy pequeño que no sea cero, lo que puede causar un resultado inesperado después de la división. Si desea tratar los números "cercanos a cero" como cero, una tolerancia sería apropiada. Sin embargo, esto depende completamente de su aplicación y objetivos.

Si su compilador usa estándares IEEE 754 para el manejo de excepciones , entonces divida por cero, así como una división por un valor que sea lo suficientemente pequeño como para causar un desbordamiento, ambos resultarían en un valor de +/- infiniti. Esto podría significar que podría querer incluir el cheque para números muy pequeños (que causarían un desbordamiento en su plataforma). Por ejemplo, en Windows , tanto float como double ajustan a las especificaciones, lo que podría causar que un divisor muy pequeño creara +/- infiniti, al igual que un valor cero.

Si su compilador / plataforma no cumple con los estándares de punto flotante IEEE 754, entonces creo que los resultados son específicos de la plataforma.


La división de punto flotante por cero no es un error. Plantea una excepción de coma flotante (que no es operativa a menos que los esté comprobando activamente) en implementaciones que admiten excepciones de coma flotante y tiene un resultado bien definido: infinito positivo o negativo (si el numerador es distinto de cero) o NAN (si el numerador es cero).

También es posible obtener infinito (y una excepción de desbordamiento) como resultado cuando el denominador es distinto de cero pero muy cercano a cero (por ejemplo, subnormal), pero nuevamente esto no es un error. Es solo cómo funciona el punto flotante.

Editar: Tenga en cuenta que, como ha señalado Eric en los comentarios, esta respuesta asume los requisitos del Anexo F, una parte opcional del estándar C que detalla el comportamiento de coma flotante y que lo alinea con el estándar IEEE para coma flotante. En ausencia de aritmética IEEE, C no define la división de coma flotante por cero (y de hecho, los resultados de todas las operaciones de punto flotante están definidos por la implementación y pueden definirse como sin sentido completo y aún así cumplir con el estándar C), por lo que usted está lidiando con una implementación de C estrafalaria que no respeta el punto flotante de IEEE, deberá consultar la documentación de la implementación que está utilizando para responder esta pregunta.


Para responder la pregunta en el título de su publicación, dividir por un número muy pequeño no causará una división entre cero, pero puede hacer que el resultado se convierta en un infinito:

double x = 1E-300; cout << x << endl; double y = 1E300; cout << y << endl; double z = y / x; cout << z << endl; cout << (z == std::numeric_limits<double>::infinity()) << endl;

Esto produce el siguiente resultado:

1e-300 1e+300 inf 1


Sí, dividir por números pequeños puede causar los mismos efectos que dividir por cero, incluidas las trampas, en algunas situaciones.

Algunas implementaciones de C (y algunos otros entornos informáticos) pueden ejecutarse en un modo de flujo descendente, especialmente si se utilizan opciones de alto rendimiento. En este modo, dividir por un denormal puede causar el mismo resultado que dividir por cero. El modo de flujo bajo flujo no es raro cuando se usan instrucciones vectoriales (SIMD).

Los números denormales son aquellos con el mínimo exponente en el formato de punto flotante que son tan pequeños que el bit implícito del significado es 0 en lugar de 1. Para IEEE 754, precisión simple, este es un número distinto de cero con una magnitud menor que 2 -126 . Para la precisión doble, es un número distinto de cero con una magnitud inferior a 2 -1022 .

Manejar correctamente los números denormales (de acuerdo con IEEE 754) requiere tiempo de computación adicional en algunos procesadores. Para evitar este retraso cuando no es necesario, los procesadores pueden tener un modo que convierta los operandos denormales a cero. Dividir un número por un operando denormal producirá el mismo resultado que dividir por cero, incluso si el resultado habitual fuera finito.

Como se señala en otras respuestas, dividir por cero no es un error en las implementaciones C que adoptan el Anexo F del estándar C. No todas las implementaciones que sí lo hacen. En las implementaciones que no lo hacen, no puede estar seguro de si las capturas de coma flotante están habilitadas, en particular la trampa para la excepción de división por cero, sin especificaciones adicionales sobre su entorno.

Dependiendo de su situación, también puede tener que protegerse contra otro código en su aplicación que altera el entorno de coma flotante.


Solo una división por exactamente 0.f levantará una división por cero excepción.

Sin embargo, la división por un número realmente pequeño puede generar una excepción de desbordamiento; el resultado es tan grande que ya no puede representarse mediante un flotante. La división devolverá el infinito.

La representación flotante de infinito se puede utilizar en los cálculos, por lo que es posible que no sea necesario verificar si el resto de la implementación puede manejarlo.