2009-06-24 12 views
13

¿Es una buena idea usar NaN de coma flotante IEEE754 (no un número) para valores que no están definidos por razones no matemáticas?¿Es una buena idea usar NaN de punto flotante IEEE754 para los valores que no están configurados?

En nuestro caso, aún no están configurados porque los valores no se han recibido de algún otro dispositivo. El contexto es un sistema integrado que usa valores IEC1131 REAL32. Edit: El lenguaje de programación es C, por lo que probablemente usaríamos NAN e isnanf (x), que son de C99. Aunque es posible que necesitemos algunas contorsiones adicionales para obtener estos en nuestra capa de compatibilidad del sistema operativo.

El valor predeterminado en los lenguajes de programación parece ser inicializar variables de punto flotante con cero positivo, cuya representación interna es cero. Eso no es utilizable para nosotros, porque 0 está en el rango de valores válidos.

Parece una solución limpia para usar NaN, pero tal vez es más complicado de lo que vale y debemos elegir algún otro valor?

+0

No sé C, pero en .NET 1.1 antes de que salieran tipos anulables, mucha gente solía usar cosas como el valor mínimo (int.MinValue). El problema con esto es que debes factorizarlo en todas partes y asegurarte de que nunca uses MinValue. Quizás existe algo parecido a eso en C? – RichardOD

+1

He hecho una pregunta similar (pero no la misma), quizás las respuestas también pueden ayudarte. http://stackoverflow.com/questions/787828/nan-as-a-special-argument – quinmars

Respuesta

10

Acaba de darse cuenta de esta cuestión.

Este es uno de los usos de NaN que el comité IEEE 754 tiene en mente (yo era un miembro del comité). Las reglas de propagación para NaN en aritmética lo hacen muy atractivo, porque si tiene un resultado de una secuencia larga de cálculos que implican algunos datos inicializados, no confundirá el resultado con un resultado válido. También puede hacer un seguimiento a través de sus cálculos para encontrar dónde está utilizando los datos inicializados mucho más sencillo.

Dicho esto, hay algunas trampas que están fuera del control del comité 754: como han señalado otros, no todo el hardware admite valores de NaN a velocidad, lo que puede ocasionar riesgos de rendimiento. Afortunadamente, con frecuencia no se realizan muchas operaciones con los datos inicializados en una configuración de rendimiento crítico.

+0

Aceptado porque usamos NaN para undefined en este caso, aunque resultó ser más complicado de lo esperado. Eso se debió principalmente a que faltó el soporte de NaN en nuestras herramientas y sistemas o fallaron y tuvimos que trabajar en eso. – starblue

3

He usado NaNs en situaciones similares solo por eso: el valor de inicialización predeterminado 0 es también un valor válido. Los NaN funcionan bien hasta ahora.

Es una buena pregunta, por cierto, por qué el valor de inicialización predeterminado suele ser (por ejemplo, en los tipos primitivos Java) 0 y no NaN. ¿No podría ser también 42 o lo que sea? Me pregunto cuál es la razón de ser de los ceros.

+1

Creo que la razón para usar 0 es que la memoria se inicializa con cero bytes independientemente del tipo, por ejemplo, en el segmento BSS de C – starblue

+0

Sí, probablemente sea algo así.Pero ahora que los diseñadores del lenguaje/compilador se han esforzado por inicializar la memoria, ¿no sería casi tan fácil inicializar a cualquier valor arbitrario (distinto de cero)? Los ceros son solo bits entre otros :-) –

+2

@ mad-j: desea iniciar toda la memoria con el mismo patrón de bits. Entonces no podría ser 42, porque entonces generalmente tendrías que hacer algo diferente para dos cortos adyacentes que lo que harías para un int. Esto deja 0 y -1. Pero 0xffffffff no es -1 como float, entonces tendrías una inconsistencia allí. No hay mucho en eso, pero creo que 0 es probablemente el mejor. Además, algunos dispositivos pueden eficientemente 0 bloques enteros de memoria física a la vez, por lo que eso vale. –

0

Si su necesidad básica es tener un valor de punto flotante que no represente ningún número que podría haberse recibido del dispositivo, y si el dispositivo garantiza que nunca devolverá NaN, entonces parece razonable yo.

Sólo recuerde que dependiendo de su entorno, es probable que tenga una forma especial de detección de NaN (no sólo tiene que utilizar if (x == float.NaN) o lo que su equivalente es.)

+0

No crea esta respuesta. Todo lo que Jon Skeet tiene que hacer es pensar en la variable y se definirá a sí mismo. –

+0

El valor se define antes de Skeet cosas de un nombre de variable, ¿verdad? – glasnt

4

NaNs son una opción razonable para un 'sin valor' oracional (el lenguaje de programación D los utiliza para inicializar los valores, por ejemplo), pero debido a las comparaciones que involucran ellos serán falsos, puede obtener algunas sorpresas:

  • if (result == DEFAULT_VALUE), no funcionará como se espera si DEFAULT_VALUE es NaN, como mencionó Jon.

  • También pueden causar problemas con la comprobación de rango si no tiene cuidado. Consideremos la función:

 
bool isOutsideRange(double x, double minValue, double maxValue) 
{ 
    return x < minValue || x > maxValue; 
} 

Si x es NaN, esta función podría informar incorrectamente que x está entre minValue y maxValue.

Si solo quieres un valor mágico para que los usuarios prueben, te recomendaría un infinito positivo o negativo en lugar de NaN, ya que no viene con las mismas trampas. Utilice NaN cuando lo desee por su propiedad para que cualquier operación en un NaN resulte en un NaN: es útil cuando no quiere confiar en que los llamadores verifiquen el valor, por ejemplo.

[Editar: Inicialmente pude escribir "cualquier comparación que los involucre será cierto" más arriba, que no es lo que quise decir, y está mal, todos son falsos, ¡aparte de NaN!= NaN, que es verdadero]

+0

¿Qué idioma usa estas reglas de comparación? Tal vez D lo hace. Pero al menos C y C++ no funcionan con NaN de esta manera. Todas las comparaciones de pedidos serán falsas. x == NaN es falso para cualquier x, incluido NaN. –

+1

No, su función solo informa que no está fuera del rango. No es ni dentro ni fuera, lo que puede confundir ingenuamente a quienes usan números en coma flotante. – starblue

+0

@Igor: Estamos diciendo lo mismo aquí. isOutsideRange devolvería falso si x es NaN, lo que implica que está dentro del rango, que no lo es. – jskinner

1

Tengo la sensación de que es un poco raro, pero al menos todos los demás números que realiza operaciones con este valor NaN dan NaN como resultado, cuando ve un NaN en un informe de error, al menos usted sabe qué tipo de error está buscando.

2

Ten cuidado con NaN ... pueden extenderse como reguero de pólvora si no tienes cuidado.

Son un valor perfectamente válido para los flotadores, pero cualquier asignación que los involucre también será igual a NaN, por lo que se propagan a través de su código. Esto es bastante bueno como una herramienta de depuración si lo captas, sin embargo, también puede ser una verdadera molestia si traes algo para lanzar y hay un caso marginal en alguna parte.

D utiliza esto como justificación para dar flotantes NaN como valor predeterminado. (Con el que no estoy seguro estoy de acuerdo.)

+9

Err ... ¿No es solo el sentido de NaNs que se propagarán? Es mucho mejor tener NaN como resultado, lo que indica que hay algo mal, que tener un número inocente pero totalmente incorrecto (que resultaría del uso accidental de números inicializados en cero). –

+1

Sí y no, porque cuando detecta NaN solo mira la salida o examinando explícitamente NaN. La consecuencia de esto es que los errores pueden detectarse mucho más tarde de lo que surgen. Por otro lado, si usa valores NULL (si es posible), obtiene un error de segmentación/NPE bastante rápido. Brutal, pero eficiente. –

+0

Si todo lo que sabe es que los NaN están en todas partes, no ayuda exactamente a descubrir de dónde vienen. – corsiKa

3

Creo que es una mala idea en general. Una cosa a tener en cuenta es que la mayoría de las CPU tratan a Nan mucho más lentamente que el flotador "habitual". Y es difícil garantizar que nunca tendrá a Nan en la configuración habitual. Mi experiencia en computación numérica es que a menudo trae más problemas de los que vale.

La solución correcta es evitar la codificación de "ausencia de valor" en el flotador, pero señalizarlo de otra manera. Sin embargo, eso no siempre es práctico, dependiendo de su base de código.

0

Esto suena como un buen uso para nans para mí. Ojalá lo hubiera pensado ...

Claro, se supone que se propagan como un virus, ese es el punto.

Creo que usaría nan en lugar de uno de los infinitos. Podría ser bueno usar un nanómetro de señalización y hacer que cause un evento en el primer uso, pero para entonces es demasiado tarde y debería apagarse en el primer uso.

0

El uso de NaN como valor predeterminado es razonable.

Tenga en cuenta que algunas expresiones, como (0.0/0.0), devuelven NaN.

Cuestiones relacionadas