Pregunta ¿Usando NaN en C ++?


¿Cuál es la mejor manera de usar NaNs en C ++?

encontré std::numeric_limits<double>::quiet_NaN() y std::numeric_limits<double>::signaling_NaN(). Me gustaría usar signaling_NaN para representar una variable no inicializada de la siguiente manera:

double diameter = std::numeric_limits<double>::signaling_NaN();

Esto, sin embargo, señala (genera una excepción) en la asignación. Quiero que haga una excepción sobre el uso, no sobre la asignación.

¿Hay alguna manera de usar signaling_NaN sin levantar una excepción en la asignación? ¿Hay una alternativa buena y portátil para signaling_NaN que levantará una excepción de punto flotante cuando se usa?


32
2017-10-24 21:56


origen


Respuestas:


Después de investigar esto un poco más, parece signaling_NaN es inútil según lo previsto. Si las excepciones de coma flotante están habilitadas, llamarlas cuenta como procesar un NaN de señalización, por lo que inmediatamente genera una excepción. Si las excepciones de coma flotante están deshabilitadas, entonces el procesamiento de un NaN de señalización lo degrada automáticamente a un NaN silencioso, por lo que signaling_NaN no funciona de ninguna manera.

Código de Menkboy funciona, pero tratar de usar NaN de señalización se encuentra con otros problemas: no hay una forma portátil de habilitar o deshabilitar las excepciones de punto flotante (como se alude a aquí y aquí), y si confía en que se habiliten excepciones, el código de un tercero puede deshabilitarlas (como se describe aquí)

Entonces parece La solución de Motti es realmente la mejor opción.


11
2017-11-11 18:32



Lo que significa NAN de señalización es que cuando la CPU se encuentra con él, se dispara una señal (de ahí el nombre). Si desea detectar variables no inicializadas, al subir el nivel de advertencia en su compilador generalmente se detectan todas las rutas que usan valores no inicializados. De lo contrario, puede usar una clase contenedora que almacene un booleano que diga si el valor está inicializado:

template <class T>
class initialized {
    T t;
    bool is_initialized;
public:
    initialized() : t(T()), is_initialized(false) { }
    initialized(const T& tt) : t(tt), is_initialized(true) { }
    T& operator=(const T& tt) { t = tt; is_initialized = true; return t; }
    operator T&() {
         if (!is_initialized)
             throw std::exception("uninitialized");
         return t; 
   }
};

9
2017-10-25 20:02



Puede escribir un NaN de señalización en una variable sin activar una excepción con algo como esto (nb: no probado)

void set_snan( double &d )
{
    long long *bits = (long long *)&d;
    *bits = 0x7ff0000080000001LL;
}

Funcionará en la mayoría de los lugares, pero no, no es 100% portátil.


3
2017-10-24 22:35



Bueno, cuidando la definición de NaN silencioso y de señalización, realmente no puedo distinguir nada.

Puede usar el código que se usa en esas funciones usted mismo, quizás impida una excepción de esa manera, pero al no ver ninguna excepción en esas dos funciones, creo que podría estar relacionado con otra cosa.

Si quiere asignar directamente el NaN:

double value = _Nan._Double;

3
2017-10-25 19:57



Respuesta simple: Haga algo como esto en el archivo de encabezado y úselo en cualquier otro lugar:

#define NegativeNaN log(-1)

Si desea hacer algún tipo de manipulaciones sobre ellos, mejor escriba alguna función de envoltura extendida alrededor de exp() me gusta extended_exp() ¡y así!


3
2017-11-05 15:49



Su implementación en C ++ puede tener una API para acceder al entorno de punto flotante para probar y borrar ciertas excepciones de coma flotante. Ver mi respuesta a una pregunta relacionada para más información.


0
2017-10-24 22:42