views:

7589

answers:

8
+12  Q: 

Using NaN in C++?

What's the best way to use NaNs in C++?

I found std::numeric_limits<double>::quiet_NaN() and std::numeric_limits<double>::signaling_NaN(). I'd like to use signaling_NaN to represent an uninitialized variable as follows:

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

This, however, signals (raises an exception) on assignment. I want it to raise an exception on use, not on assignment.

Is there any way to use signaling_NaN without raising an exception on assignment? Is there a good, portable alternative to signaling_NaN that will raise a floating point exception when used?

+2  A: 

You can write a signalling NaN into a variable without triggering an exception with something like this (nb: untested)

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

It'll work most places, but no, it's not 100% portable.

Menkboy
A: 

Your C++ implementation may have an API for accessing the floating point environment to test for and clear certain floating point exceptions. See my answer to a related question for more information.

jwfearn
+1  A: 

Well... storing a signaling_NaN is probably considered using it.

MSN

MSN
A: 

Maybe this @boost.org can help.

codeguru
+1  A: 

Well, looking after the definition of both quiet and signaling NaN, I can't really make out any difference.

You could use the code that is used in those functions yourself, maybe it prevents an exception that way, but seeing no exception in those two functions, I think it might be related to something else.

If you want to directly assign the NaN:

double value = _Nan._Double;
HS
+3  A: 

What signaling NAN means is that when the CPU encounters it a signal is fired, (hence the name). If you want to detect uninitialized variables then raising the warning level on your compiler usually detects all paths that use uninitalized values. Failing that you can use a wrapper class that stores a boolean saying if the value is initialized:

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; 
   }
};
Motti
A: 

Try turning off floating point exceptions in the compiler settings or using the quiet NaN.

Jasper Bekkers
+3  A: 

After looking into this some more, it looks like signaling_NaN is useless as provided. If floating point exceptions are enabled, then calling it counts as processing a signaling NaN, so it immediately raises an exception. If floating point exceptions are disabled, then processing a signaling NaN automatically demotes it to a quiet NaN, so signaling_NaN doesn't work either way.

Menkboy's code works, but trying to use signaling NaNs runs into other problems: there's no portable way to enable or disable floating point exceptions (as alluded to here and here), and if you're relying on exceptions being enabled, third party code may disable them (as described here).

So it seems like Motti's solution is really the best choice.

Josh Kelley