Pregunta

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

En nuestro caso, todavía no están configurados porque los valores no se han recibido de otro dispositivo. El contexto es un sistema embebido que utiliza valores IEC1131 REAL32. Editar: 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 incorporarlas a nuestra capa de compatibilidad de sistema operativo.

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

Parece una solución limpia para usar NaN, pero ¿quizás sea más complicado de lo que vale y deberíamos elegir algún otro valor?

¿Fue útil?

Solución

Acabo de notar esta pregunta.

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

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

Otros consejos

Los NaN son una opción razonable para un enunciado 'sin valor' (el lenguaje de programación D los usa para valores no inicializados, por ejemplo), pero debido a que cualquier comparación que los involucre será falsa, puede obtener algunas sorpresas:

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

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

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

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

Si solo desea un valor mágico para que los usuarios lo prueben, recomendaría infinito positivo o negativo en lugar de NaN, ya que no viene con las mismas trampas. Use NaN cuando lo desee por su propiedad de que cualquier operación en un NaN resulta en un NaN: es útil cuando no desea confiar en que las personas que llaman verifican el valor, por ejemplo.

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

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

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

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 de lo habitual. flotador. Y es difícil garantizar que nunca tendrá a Nan en la configuración habitual. Mi experiencia en informática numérica es que a menudo trae más problemas de los que merece.

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

Tenga cuidado con los NaN ... pueden propagarse como un incendio forestal si no tiene cuidado.

Son un valor perfectamente válido para flotantes, 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 herramienta de depuración si lo detecta, sin embargo, también puede ser una verdadera molestia si trae algo para liberar y hay un caso marginal en alguna parte.

D usa esto como justificación para dar flotadores NaN por defecto. (Con lo que no estoy seguro de estar de acuerdo).

Creo que es un poco confuso, pero al menos cualquier otro número que realice operaciones con este valor de NaN da como resultado NaN: cuando ve un NaN en un informe de error, al menos sabe qué tipo de error está cometiendo. caza.

Si su necesidad básica es tener un valor de coma 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 me parece razonable.

Solo recuerda que dependiendo de tu entorno, probablemente necesites una forma especial de detectar NaNs (no solo uses if (x == float.NaN) o lo que sea tu equivalente.)

Esto me parece un buen uso para nans. 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. Puede ser bueno usar un nan de señalización y hacer que provoque un evento en el primer uso, pero para entonces es demasiado tarde debería quedar en silencio en el primer uso.

Usar NaN como valor predeterminado es razonable.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top