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?
NaN is unordered: it is not equal to, greater than, or less than anything, including itself. x == x is false if the value of x is NaN. You can use this to test whether a value is NaN or not, but the recommended way to test for NaN is with the isnan function (see Floating-Point Number Classification Functions).
Returns a quiet NaN (Not-A-Number) value of type double . The NaN values are used to identify undefined or non-representable values for floating-point elements, such as the square root of negative numbers or the result of 0/0.
Unquoted literal constant NaN is a special value representing Not-a-Number. Since NaN always compares unequal to any number, including NaN, it is usually used to indicate an error condition for a function that should return a valid number. Note − Use the isNaN() global function to see if a value is an NaN value.
NaN stands for Not A Number and is one of the common ways to represent the missing value in the data. It is a special floating-point value and cannot be converted to any other type than float. NaN value is one of the major problems in Data Analysis.
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; } };
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With