2008-10-24 60 views
31

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

Encontré std::numeric_limits<double>::quiet_NaN() y std::numeric_limits<double>::signaling_NaN(). Me gustaría utilizar signaling_NaN para representar una variable sin inicializar de la siguiente manera:

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

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

¿Hay alguna forma de usar signaling_NaN sin generar una excepción en la asignación? ¿Existe una buena alternativa portátil a signaling_NaN que genere una excepción de punto flotante cuando se usa?

+0

hmm ... estoy jugando con esto porque soy curioso ahora, pero no pude conseguir mina para lanzar una excepción. ¿Qué hiciste para obtener la excepción? –

+0

@JeffreyMartinez No es una excepción C++ normal, si eso es lo que estás pensando. Es una excepción de punto flotante: vea las notas [aquí] (http://en.cppreference.com/w/cpp/numeric/fenv). – bames53

Respuesta

11

Después de mirar en esta un poco más, parece que signaling_NaN es inútil como siempre. 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.

Menkboy's code obras, pero tratando de utilizar la señalización NaNs se encuentra con otro problema: no hay manera portátil para activar o desactivar las excepciones de coma flotante (como se alude here y here), y si usted está confiando en excepciones siendo activada, tercero código de parte puede deshabilitarlos (como se describe here).

Parece que Motti's solution es realmente la mejor opción.

3

puede escribir un NaN de señalización en una variable sin desencadenar una excepción con algo como esto (NB: no probado)

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

que va a trabajar la mayoría de los lugares, pero no, no es 100% portátil.

0

Su implementación en C++ puede tener una API para acceder al entorno de coma flotante para probar y borrar ciertas excepciones de coma flotante. Consulte my answer to a related question para obtener más información.

3

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

Puede utilizar el código que se utiliza en esas funciones usted mismo, tal vez 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 desea asignar directamente el NaN:

double value = _Nan._Double; 
9

Lo NAN de señalización significa es que cuando la CPU se encuentra con que 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. En su defecto se puede utilizar una clase de contenedor que almacena un valor booleano que dice si se ha inicializado el valor:

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; 
    } 
}; 
+4

'impulso :: opcional ' es una buena alternativa a esto, y funciona bien para los valores de retorno, variables locales y miembros. Además, no llama al constructor predeterminado, y funciona en su mayor parte con tipos de referencia. – rvalue

3

Respuesta simple: hacer algo como esto en el archivo de cabecera y lo utilizan en todas partes:

#define NegativeNaN log(-1) 

Si desea hacer algún tipo de manipulaciones en ellos una mejor escribir algo de función de envoltura extendida alrededor exp() como extended_exp() ¡y así!