Pregunta

¿Cuál es la mejor manera de utilizar los Nan en C++?

He encontrado std::numeric_limits<double>::quiet_NaN() y std::numeric_limits<double>::signaling_NaN().Me gustaría utilizar signaling_NaN para representar una variable no inicializada como sigue:

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

Esto, sin embargo, las señales (levanta una excepción) en la asignación.Quiero elevar una excepción en el uso, no en la asignación.

¿Hay alguna forma de usar signaling_NaN sin levantar una excepción en la asignación?Es un buen portátil, alternativa a la signaling_NaN que levantar una excepción de punto flotante cuando se utiliza?

¿Fue útil?

Solución

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

El código de Menkboy funciona, pero intentar usar la señalización de NaNs se encuentra con otros problemas: no hay una forma portátil de habilitar o deshabilitar excepciones de punto flotante (como se alude a aquí y aquí ), y si confía en que las excepciones estén habilitadas , el código de terceros puede deshabilitarlos (como se describe aquí ).

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

Otros consejos

Lo que significa NAN de señalización es que cuando la CPU lo encuentra, se dispara una señal (de ahí el nombre). Si desea detectar variables no inicializadas, elevar el nivel de advertencia en su compilador generalmente detecta todas las rutas que usan valores no inicializados. Si no puede usar una clase de contenedor que almacena un refrán booleano si el valor se inicializa:

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

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.

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

Puede usar el código que se usa en esas funciones usted mismo, tal vez evite 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;

Respuesta Simple:Hacer algo como esto en el encabezado de archivo y utilizarlo en cualquier otro lugar:

#define NegativeNaN log(-1)

Si desea hacer algún tipo de manipulaciones en la mejor escribir algunos extendida función de contenedor alrededor de exp() como extended_exp() y así sucesivamente!

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

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