c++ - superlativo - estructura de comparativos en ingles
Floating Point, ¿es una comparación de igualdad suficiente para evitar la división por cero? (2)
// value will always be in the range of [0.0 - maximum]
float obtainRatio(float value, float maximum){
if(maximum != 0.f){
return value / maximum;
}else{
return 0.f;
}
}
El rango maximum
puede ser cualquier cosa, incluidos los números negativos. El rango de value
también puede ser cualquier cosa, aunque la función solo es necesaria para tener "sentido" cuando la entrada está en el rango de [0.0 - maximum]
. La salida siempre debe estar en el rango de [0.0 - 1.0]
Tengo dos preguntas que me pregunto, con esto:
- ¿Es esta comparación de igualdad suficiente para garantizar que la función nunca se divida por cero?
- Si el valor máximo es degenerado (extremadamente pequeño o extremadamente grande), ¿existe la posibilidad de que la función arroje un resultado fuera de [0.0 - 1.0] (suponiendo que el valor esté en el rango correcto)?
En este caso con el rango limitado, debería estar bien. En general, un chequeo de cero primero evitará la división por cero, pero todavía hay una posibilidad de desbordamiento si el divisor está cerca de cero y el dividendo es un número grande, pero en este caso el dividendo será pequeño si el divisor es pequeño (ambos podrían estar cerca de cero sin causar un desbordamiento).
Aquí hay una respuesta tardía que aclara algunos conceptos en relación con la pregunta:
Solo devuelve valor / máximo
En punto flotante, la división por cero no es un error fatal como la división entera por cero. Como sabe que el value
está entre 0.0
y maximum
, la única división por cero que puede ocurrir es 0.0 / 0.0
, que se define como producción de NaN
. El valor de coma flotante NaN
es un valor perfectamente aceptable para la función obtainRatio
a devolver, y de hecho es un valor excepcional mucho mejor que 0.0
, ya que la versión propuesta está volviendo.
Las supersticiones sobre el punto flotante son solo supersticiones
No hay nada aproximado sobre la definición de <=
entre flotadores . a <= b
veces no se evalúa como verdadero cuando a
está un poco por encima de b
. Si a
y b
son dos variables de float
finita, a <= b
evalúa a verdadero exactamente cuando la razón representada por a
es menor o igual que la razón representada por b
. El único pequeño error que uno puede percibir no es un error, sino una interpretación estricta de la regla anterior: +0.0 <= -0.0
evalúa como verdadero, porque "el racional representado por +0.0
" y "el racional representado por -0.0
" son ambos 0.
De manera similar, no hay nada aproximado sobre ==
entre flotantes : dos variables float
finitas a
y b
hacen que a == b
verdadero si y solo si la racional representada por a
y la racional representada por b
son las mismas.
Dentro de una condición if (f != 0.0)
, el valor de f
no puede ser una representación de cero, y así una división por f
no puede ser una división por cero. La división aún puede desbordarse. En el caso particular de value / maximum
, no puede haber un desbordamiento porque su función requiere 0 ≤ value ≤ maximum
. Y no necesitamos preguntarnos si ≤
en la precondición significa la relación entre los racionales o la relación entre los flotadores, ya que los dos son esencialmente los mismos.
Dicho esto
C99 permite una precisión adicional para las expresiones de punto flotante, que los compiladores interpretaron erróneamente en el pasado como una licencia para hacer que el comportamiento de coma flotante sea errático (al punto que el programa if (m != 0.) { if (m == 0.) printf("oh"); }
se puede esperar que imprima "oh" en algunas circunstancias).
En realidad, un compilador C99 que ofrece un punto flotante IEEE 754 y define FLT_EVAL_METHOD
como un valor no negativo no puede cambiar el valor de m
después de haber sido probado. La variable m
se estableció en un valor representable como float cuando se asignó por última vez, y ese valor es una representación de 0 o no. Solo las operaciones y las constantes pueden tener una precisión excesiva (consulte el estándar C99, 5.2.4.2.2: 8).
En el caso de GCC, las versiones recientes hacen lo que es correcto con -fexcess-precision=standard
, implícito en -std=c99
.
Otras lecturas
Descripción de David Monniaux del triste estado de coma flotante en C hace algunos años (primera versión publicada en 2007). El informe de David no intenta interpretar el estándar C99, sino que describe la realidad del cálculo en coma flotante en C como lo era entonces, con ejemplos reales. La situación ha mejorado mucho desde entonces, gracias a la mejora en el cumplimiento de estándares en los compiladores que cuidan y gracias al conjunto de instrucciones SSE2 que hace que todo el tema sea discutible.
La publicación de la lista de correos de 2008 por Joseph S. Myers describiendo la situación actual de GCC con flotadores en GCC (malo), cómo interpretó el estándar (bueno) y cómo estaba implementando su interpretación en GCC (BUENO).