¿Cómo fuerzo 0.0 / 0.0 para volver a cero en lugar de NaN en MIPSPro compilador de C?
Pregunta
A medida que los estados de preguntas, estoy usando el compilador C MIPSPRo, y tengo una operación que devolverá NaN para algunos conjuntos de datos donde el numerador y denom son cero. ¿Cómo puedo evitar que esto suceda?
Solución
En los sistemas SGI con el compilador MIPSPro, se puede establecer el manejo de varias excepciones de punto flotante con gran precisión utilizando las instalaciones en sigfpe.h
. Como sucede, la división de cero por cero es uno de estos casos:
#include <stdio.h>
#include <sigfpe.h>
int main (void) {
float x = 0.0f;
(void) printf("default %f / %f = %f\n", x, x, (x / x));
invalidop_results_[_ZERO_DIV_ZERO] = _ZERO;
handle_sigfpes(_ON, _EN_INVALID, 0, 0, 0);
(void) printf("handled %f / %f = %f\n", x, x, (x / x));
return 0;
}
En uso:
arkku@seven:~/test$ cc -version
MIPSpro Compilers: Version 7.3.1.3m
arkku@seven:~/test$ cc -o sigfpe sigfpe.c -lfpe
arkku@seven:~/test$ ./sigfpe
default 0.000000 / 0.000000 = nan0x7ffffe00
handled 0.000000 / 0.000000 = 0.000000
Como se puede ver, estableciendo el resultado _ZERO_DIV_ZERO
cambia el resultado de la misma división. Del mismo modo que puede manejar la división regular por cero (por ejemplo, si no desea que el infinito como el resultado).
Por supuesto, nada de esto es estándar; sería más portátil para comprobar si hay NaN después de cada división y aún mejor para comprobar si hay ceros antes. C99 ofrece cierto control sobre el entorno de coma flotante en fenv.h
, pero no creo que nada adecuado para esta está disponible. En cualquier caso, mi viejo MIPSPro no soporta C99.
Otros consejos
El uso de una cláusula if? También tengo curiosidad por qué te gustaría hacer caso omiso de esta imposibilidad matemática. Está seguro de su entrada no está mal / sentido en este caso?
Si no te importa la introducción de un pequeño error, se puede añadir un valor pequeño para el denominador, asumiendo que está haciendo la aritmética de coma flotante. aparentemente tiene algunos pequeños valores definidos:
DBL_MIN es el más pequeño doble
DBL_EPSILON es el doble más pequeña S.T. x + DBL_EPSILON! = x
Así que me gustaría probar
#include <float.h>
#define EPS DBL_MIN
double divModified(double num, double denom) {
return num / (denom + EPS);
}
IEEE 754 (la especificación de punto flotante) dice que 0.0 / 0.0 es no es un número, es decir, NaN
. Si usted quiere que sea otra cosa, con mucho, el mejor enfoque consiste en detectar cuando los operandos son ambos cero en una cláusula if
y devolver el valor que prefiere das. Tal como esto:
#define WonkyDiv(a,b) ((a)==0.0&&(b)==0.0 ? 0.0 : (a)/(b))
float wonkyResult = WonkyDiv(numerator, denominator);