Question

Is it a good idea to use IEEE754 floating point NaN (not-a-number) for values which are undefined for non-mathematical reasons?

In our case they are not yet set because the values have not been received from some other device. The context is an embedded system using IEC1131 REAL32 values. Edit: The programming language is C, so we would most likely use NAN and isnanf(x), which are from C99. Though we may need some extra contortions to get these into our OS compatibility layer.

The default in programming languages seems to be to initialize floating point variables with positive zero, whose internal representation is all zeros. That is not usable for us, because 0 is in the range of valid values.

It seems like a clean solution to use NaN, but maybe it is more hassle than it is worth and we should pick some other value?

Was it helpful?

Solution

Just noticed this question.

This is one of the uses of NaNs that the IEEE 754 committee has in mind (I was a committee member). The propagation rules for NaNs in arithmetic make this very attractive, because if you have a result from a long sequence of calculations that involve some initialized data, you will not mistake the result for a valid result. It can also make tracing back through your calculations to find where you are using the initialized data much more straightforward.

That said, there are a few pitfalls that are outside of the 754 committee's control: as others have noted, not all hardware supports NaN values at speed, which can result in performance hazards. Fortunately, one does not often do a lot of operations on initialized data in a performance-critical setting.

OTHER TIPS

NaNs are a reasonable choice for a 'no value' sentential (the D programming language uses them for uninitialized values, for instance), but because any comparisons involving them will be false, you can get a few surprises:

  • if (result == DEFAULT_VALUE), won't work as expected if DEFAULT_VALUE is NaN, as Jon mentioned.

  • They can also cause problems with range checking if you're not careful. Consider the function:

bool isOutsideRange(double x, double minValue, double maxValue)
{
    return x < minValue || x > maxValue;
}

If x is NaN, this function would incorrectly report that x is between minValue and maxValue.

If you just want a magic value for users to test against, I'd recommend positive or negative infinity instead of NaN, as it doesn't come with the same traps. Use NaN when you want it for its property that any operations on a NaN result in a NaN: it's handy when you don't want to rely on callers checking the value, for example.

[Edit: I initially managed to type "any comparisons involving them will be true" above, which is not what I meant, and is wrong, they're all false, apart from NaN != NaN, which is true]

I have used NaNs in similar situations just because of that: the usual default initialization value 0 is also a valid value. NaNs work fine so far.

It's a good question, by the way, why the default initialization value is usually (for instance, in Java primitive types) 0 and not NaN. Couldn't it as well be 42 or whatever? I wonder what's the rationale of zeros.

I think it is a bad idea in general. One thing to keep in mind is that most CPU treat Nan much slower then "usual" float. And it is hard to guarantee you will never have Nan in usual settings. My experience in numerical computing is that it often brings more trouble than it worths.

The right solution is to avoid encoding "absence of value" in the float, but to signal it in another way. That's not always practical, though, depending on your codebase.

Be careful with NaN's... they can spread like wildfire if you are not careful.

They are a perfectly valid value for floats, but any assignments involving them will also equal NaN, so they propagate through your code. This is quite good as a debugging tool if you catch it, however it can also be a real nuisance if you are bringing something to release and there is a fringe case somewhere.

D uses this as rationale for giving floats NaN as default. (Which I'm not sure I agree with.)

My feelings are that it's a bit hacky, but at least every other numbers you make operations with this NaN value gives NaN as result - when you see a NaN in a bug report, at least you know what kind of mistake you are hunting.

If your basic need is to have a floating point value which doesn't represent any number which could possibly have been received from the device, and if the device guarantees it will never return NaN, then it seems reasonable to me.

Just remember that depending on your environment, you probably need a special way of detecting NaNs (don't just use if (x == float.NaN) or whatever your equivalent is.)

This sounds like a good use for nans to me. Wish I had thought of it...

Sure, they are supposed to propagate like a virus, that is the point.

I think I would use nan instead of one of the infinities. It might be nice to use a signaling nan and have it cause an event on the first use, but by then its too late it should go quiet on the first use.

Using NaN as a default value is reasonable.

Note that some expressions, such as (0.0 / 0.0), return NaN.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top