views:

134

answers:

3

I have g++ 4.4.3 on Linux with Ubuntu Lucid Lynx, and I am getting a:

-nan

as a result. On Hardy Heron with g++ 4.3.1, I am getting all

nan

This is causing my text diff regression to fail, since I am using cout to print this numerical result.

What is the meaning of a signed nan, and is there a way to tell the compiler that an unsigned nan is sufficient?

+5  A: 

You can get a signed NaN since the NaN-ness of the value and the sign of the value are controlled by different bits in IEEE754 (NaN is simply indicated by special exponent values, distinct from the sign bit). I'm at a loss as to what sort of operation would do it though.

It's possible that one of the normal operations that produce NaN could be causing a negative variation (like +0/-0 or +Inf/-Inf). But I would have thought that NaNs would print as nan regardless of sign.

However, while the standard specifies in great detail how numbers are handled, it's strangely silent on how they're printed. The Wikipedia page for NaN lists these:

nan         NaN         NaN%        NAN         NaNQ
NaNS        qNaN        sNaN        1.#SNAN     1.#QNAN
-1.#IND     -NaN        NaN12345    -sNaN12300

with some of those showing sign and the extra payload.

Note that I'm talking about the IEEE standards here. The ISO C standards do indicate a limited number of forms but whether the sign and/or payload is printed is implementation-dependent. I can only assume that the later versions of the library have changed their behaviour.

How to fix it within the compiler, I'm not sure. I'd just take the pragmatic approach and run your output file through something like sed 's/-nan/nan/g'. Hopefully that won't introduce other problems.

And you should also keep an ey on the form that allows the payload to be printed as well, though I'd only worry about that when the tests start failing again. But I'd put a comment somewhere near that sed command indicating that it may happen at some time in the future. That way, at least the guy that follows you will understand why.

paxdiablo
I can filter the result, but I just want to make sure my reasoning is legitimate when someone sees the filtering.
Juan
The standard itself defines it as NaN when exponent is the max value and mantissa is of a certain format. Sign doesn't come into it. I would simply chalk it up to simplistic output routine that checked the sign regardless of whether it was outputting a real numbers or one of the specials.
paxdiablo
+1  A: 

Signed NaN is possible, though I don't know enough about floating point to know why one platform would produce -NaN and another would produce NaN. But since NaN has some unusual behaviors, I'm really not surprised that that could happen.

Here's a snippet from the C99 document description for formatted floating point I/O:

A double argument representing a NaN is converted in one of the styles [-]nan or [-]nan(n-char-sequence) — which style, and the meaning of any n-char-sequence, is implementation-defined. The F conversion specifier

You can use copysign() to get the sign of a NaN value. An example from the C99 document:

if (isnan(c)) c = copysign(0.0, c);

But as paxdiablo indicated, it might be easier to allow for the "-nan" result in your test scripts.

Michael Burr
+7  A: 

The change in behaviour may be due to libraries rather than the compiler. There is certainly a change in glibc around the right sort of time - from the entry for 2009-08-23 at line 2528 in ChangeLog.17 in the glibc source:

...
     * stdio-common/printf_fp.c: ISO C expects to print the sign of NaN
     as well.
...
Matthew Slattery
Incredible find. The exact same binary copied to the newer machine results in the -nan. Excellent work!
Juan
Actually, ISO C _doesn't_ expect to print the sign, it's left as implementation-dependent. Don't let me detract from your answer though, it was a good find, and no doubt the reason why the behaviour changed.
paxdiablo