What does -1.#IND mean?: A survey of how the Visual C runtime library prints special floating point values

As every computer scientist knows, the IEEE floating point format reserves a number of representations for infinity and non-numeric values (collectively known as NaN, short for not a number). If you try to print one of these special values with the Visual C runtime library, you will get a corresponding special result:

Output Meaning
1#INF Positive infinity
-1#INF Negative infinity
1#SNAN Positive signaling NaN
-1#SNAN Negative signaling NaN
1#QNAN Positive quiet NaN
-1#QNAN Negative quiet NaN
1#IND Positive indefinite NaN
-1#IND Negative indefinite NaN

Positive and negative infinity are generated by arithmetic overflow, or when the mathematical result of an operation is infinite, such as taking the logarithm of positive zero. (Don't forget that IEEE floating point supports both positive and negative zero.) For math nerds: IEEE arithmetic uses affine infinity, not projective, so there is no point at infinity.

Signaling and quiet NaNs are not normally generated by computations (with one exception noted below), but you can explicitly create one for a floating-point type by using the std::numeric_limits<T> class, methods signaling_NaN() and quiet_NaN().

Recall that there is not just one signaling and quiet NaN, but rather a whole collection of them. The C runtime does not distinguish among them when printing, however. All signaling NaNs are reported as 1#SNAN, regardless of the signal bits. The C runtime does report the sign of the NaN, for what little that is worth.

The weird one is the Indefinite NaN, which is a special type of quiet NaN generated under specific conditions. If you perform an invalid arithmetic operation like add positive infinity and negative infinity, or take the square root of a negative number, then the IEEE standard requires that the result be a quiet NaN, but it doesn't appear to specify what quiet NaN exactly. Different floating point processor manufacturers chose different paths. The term Indefinite NaN refers to this special quiet NaN, whatever the processor ends up choosing it to be.

Some floating point processors generate a quiet NaN with the signal bits clear but the sign bit set. Setting the sign bit makes the result negative, so on those processors, you will see the indefinite NaN rendered as a negative indefinite NaN. (The x86 is one of these processors.)

Other floating point processors generate a quiet NaN with the signal bits and the sign bit all clear. Clearing the sign bit makes the result positive, so on those processors, you will see the indefinite NaN rendered as a positive indefinite NaN.

In practice, the difference is not important, because either way, you have an indefinite NaN.

Comments (29)
  1. Lockwood says:

    And the favourite side dish at my local Indian takeaway is an indefinite NaN

  2. Joshua says:

    Amazing that √(-1) and (-∞ + ∞) both return the same kind of NAN as one is on the line (but you don't know where) and the other is off the line.

  3. Roger says:

    Somewhat related is that dividing -2147483648 (signed 32 bit minimum value) by minus one generates a cpu exception on Intel processors (in the same way as dividing by zero does).  The immediate reason is that positive 2147483648 does not fit, and there is no infinity/nan equivalent for integers.  I had to add explicit checks in some of my code.  Originally seen at kqueue.org/…/idiv-dos showing how to crash various pieces of software.  I wonder if there is some way to get the kernel or critical user space apps to perform the calculation.

  4. Incidentally, the fact that a NaN compares different from itself constitutes a quick way to check for NaNs – in some code of mine, where there are licit cases in which a NaN could be around, there are several weird-looking if(x!=x) around that puzzled several people. :)

  5. SpecLad says:

    So if all signaling NaNs are printed as #SNAN, the #IND ones must be quiet. So what's the difference, then, between #IND and #QNAN?

    [As I noted in the article, #IND is a special type of #QNAN. -Raymond]
  6. j b says:

    Matteo Italia,

    I would have been puzzled, too (I wasn't aware of NaN comparing different from itself). If I had seen something like that, and had it explained, I would have walked up to the responsible programmer and ordered him to add an expanatory end-of-line comment to the statement :-)

    But I wonder: Wouldn't many optimizing compilers determine at compile time that the expression will always be false, issue a warning (or error), and generate no code for the entire if-clause, treating an else-clause, if present, as unconditional code? You could of course force non-optimizaton by declaring x to be volatile, but that could prevent a lot of other optimization as well.

  7. ChrisR says:

    @j b:  If you don't understand these things, then I don't think it makes sense for you to be in a position where you are making any orders.  Regarding your query, why don't you get out your compiler and try it?  A test on my machine using VS2010 SP1 and the default "Release" build settings shows that the optimizer does not optimize away the floating point comparison.  This makes sense to me, especially given the fact that NaNs always compare as unequal.

  8. Christian says:

    The best thing about NANs is that in LuaJit they are used to store pointers and integers and the type information inside the available bits of a double :-)

  9. JM says:

    @j b: "volatile" is not a magic marker that suppresses optimizations. I know it's convenient to use it as such in quick benchmarking situations, but do not, in production code, add "volatile" in a misguided attempt to suppress optimizations. Aside from that, floating-point and optimizations are a veritable minefield; adding "volatile" certainly never improves matters.

    A quick way to check for NaN that doesn't require comments is to use, wait for it, isnan(). #include <math.h>. Section of the C standard, right there, standard library, no need for shenanigans. "I optimized the NaN check" is not something I want to be around to hear. Anywhere.

  10. Zan Lynx' says:

    "if (x != x)" does look very confusing and I'd never expect that to be true. "isnan(x)" is much clearer.

    What is even more confusing about floating point math is that "x = y; z = y; if (x != z)" may very well return true because of 64-bit double storage in RAM vs 80-bit storage in x87 registers.

  11. Joshua says:


    #undef isnan

    #if definded(_cplusplus) || STDC_VERSION >= 199901L

    inline isnan(float x) { return x != x; }

    inline isnan(double x) { return x != x; }

    inline isnan(long double x) { return x != x; }


    #define isnan(x) ((x) != (x))


    I suppose I should be disappointed if math.h doesn't contain that.

  12. j b says:


    "Testing can prove the presence, not the absence of errors". Transferred to this situation: Finding one compiler that does NOT do this optimization (at some given optimization level) certainly does not prove that NO compiler wo'nt do it.


    I no way meant to suggest that 'volatile' "is a magic marker that suppresses optimizations", but it does suppress SOME optimizations. I am currently programming embedded systems where any externally defined name may, at link time (so it is unknown to the compiler), be linked to a location or register connected to an external device or event, and may change at any time. So optimizations based on the assumption that the left side 'x' has the same value as the right side 'x' must be suppressed, in case 'x' was updated between the evaluation of the left and right operands of the comparison. Marking 'x' as volatile informs the compiler that it cannot assume that 'x' is unchanged througout the evaluation of the if-test, but must reloaded for every access. Any access to 'x', whether testing or other, should re-read the physical location/register, and not rely on a cached 'x' value, neither in a physical cache or from previously calculated common subexpressions.

    If 'x' was a real peripheral register/location, this extreme carefulness would certainly be justified. If it is NOT, but just a plain variable, and you (ab)use 'volatile' simply to fool the compiler to believe that 'x' might change value midway in the if-test, the compiler will know that it cannot evaluate the bool expression at compile time, by flow analaysis. So there is no risk of the if-clause being optimized away. Numerous other flow analysis based optimizations could also be suppressed, e.g. common subexpression calculations. By using 'volatile', you have told the compiler: 'Be aware! This location could change its value at any time, behind your back! Don't trust it to be unchanged! Re-evaluate any expression where it occurs, every time, even though flow analysis indicates that it couldn't possibly have changed!'

    So, (ab)using 'volatile' to make 110% sure that no compiler optimization will suppress the if-clause and all its associated code, and similar for every other place 'x' is used. The general code quality could suffer, both in time and space.

    "… adding "volatile" certainly never improves matters" – it certainly does if 'x' is a location that is updated in real time by some peripheral sensor. In an embedded system, 'volatile' is an extremely important keyword.

  13. ChrisR says:

    @j b:  I don't think I mentioned anywhere that all optimizing compilers behave the same.  Nor that I had somehow proven that they all skip the "optimization" you mentioned.  I simply picked (a fairly popular) compiler I had on my PC and tried it.  This way I could see at least one compiler's behavior for myself, rather than just pondering and speculating.

  14. hacksoncode says:

    @Lockwood: Yeah, there's something about Indian food that generates references to IEEE conventions… my friends and I call Lime Pickles ("Achaar", various spellings) "IEEE NotAFlavor pickles", because they seem to contain all flavor directions at maximum magnitude.

  15. Jim says:

    "As I noted in the article, #IND is a special type of #QNAN. -Raymond"

    This confused me too until I read your comment. Reading back, I don't think you do mention this. You say "The weird one is the Indefinite NaN." and then just seem to start talking about quiet NaNs, which seems like a switch in topic to someone like me who didn't know the connection. As the end you're still talking about quiet NaNs when suddenly you switch back to indefinite NaNs. This time it doesn't scan right at all if you think they're separate concepts, but the connection still isn't obvious if you don't already know it (again, to me at least).

    As usual, great article, but I think this would be a lot clearer if you explicitly mention that indefinite NaNs are a type of quiet NaN when you first mention the term.

    [I added a few clarifying sentences. I hope it helps. -Raymond]
  16. Joshua says:

    If you were not kidding my response would have been find a better bone to pick.

    The only annoying thing I found is vsc doesn't seem to have an option to link against an alternate C library (it does have the option to link none). Unfortunately it tends to assume that certain functions in msvcrt*.dll /are present/ when not linking against it.

  17. Jonathan Wilson says:

    I tried to find the source to isnan in the various copies of Visual C++ I have but I cant find it.

    It sounds like its one of those bits of the CRT (like say the floating point conversion routines, floating point parts of printf, lower level exception handling code etc) that Microsoft either cant or wont release.

  18. JustSomeGuy says:

    Perhaps you should look into : int isnan(float f) { return f != f; }

  19. Silly says:

    I was thinking maybe _isnan was a compiler intrinsic, but I guess that can't be the case. Maybe it works by comparing the given argument for equality to all non-NaN floating point values, returning false if no match found. Maybe it just looks at the bits and does some fancy test. Anyways, I like to do all my arithmetic in VAX-G and thus avoid the esoteric questions of infinity and not number numbers.

  20. [Wouldn't many optimizing compilers determine at compile time that the expression will always be false, issue a warning (or error), and generate no code for the entire if-clause, treating an else-clause, if present, as unconditional code? ]

    Not if they claim to conform to IEEE 754. Of course if you enable -ffast-math or equivalent flags such test will happily fail, but in that case you are explicitly asking for non-IEEE 754 compliant behavior (and many of such optimizations remove the special behavior for non-numerical values, i.e. you may not even get the NaNs when you expect them).

    [ A quick way to check for NaN that doesn't require comments is to use, wait for it, isnan(). ]

    Right, if x was actually a double; but there x was a MathVector<3, double>, which overloaded the operator==/operator!= to check all the corresponding values of the two operands; I couldn't just do "if(isnan(x))". The alternatives were adding yet another distracting for or just if(x!=x) (which, by the way, is well known idiom for anyone working with FP). Also, it *is* commented (there's something like "check for NaNs" or stuff like that).

  21. JustSomeGuy says:

    Interestingly, NONE of the possibilities listed are permitted by the ISO C standard (as at C99 anyway). Infinities are meant to be "[-]inf[inity]" (or uppercase for the %F printf variant) and all NaNs start with "[-]nan" (again uppercase for %F).

    However, since C90 is silent on the underlying representation of floating point, and does not specify what's printed for the non-specific values, I guess MS can be said to comply with *a* C standard, albeit a 20-year old one – that's gotta put it in TurboC territory surely :-)

    Just kidding, it's actually a nice product, I just can't resist taking a dig at the behemoths sometimes.

  22. Random832 says:

    What's the 1 for? (I posted this yesterday, but I think it didn't go through)

    [I don't know. My guess is so that it at least looks enough like a number so atoi won't barf. -Raymond]
  23. Mike Dimmick says:

    JustSomeGuy: Visual C++ does not claim, and never has claimed, to be a C99 compiler. It is a mostly-conformant C++98 compiler (with various C++11 extensions in more recent versions), with a selectable C90 mode.


    C99 is not a priority for Microsoft. If you want to use C99, use a different compiler.

  24. Brian_EE says:

    @j b: "In an embedded system, 'volatile' is an extremely important keyword."

    Absolutely. Of course, in fairness, you shouldn't expect Windows (or any other environment) high-level programmers to know this.

    As an embeeded hardware designer who also develops uP peripherals in FPGAs and sometimes writes the embedded C that accesses those real-time peripherals, I quickly learned the use of volatile to prevent the compiler from optimizing out repeated register reads in a loop.

  25. Matt says:


    Optimising compilers only optimise things cautiously. If X is an int, and the compiler sees if(X != X), it might say "that's always gonna be FALSE, so I can optimise it away". But if X is a float or a double, it won't optimise it, precisely BECAUSE there is a float and double (namely the NaNs) for which (X != X) is not FALSE.

  26. Matt says:


    "What is even more confusing about floating point math is that "x = y; z = y; if (x != z)" may very well return true because of 64-bit double storage in RAM vs 80-bit storage in x87 registers."

    If you're comparing floats for equality, you're Doing It Wrong(TM).

  27. nobugz says:

    Puzzler: what kind of infinity is "1.#J"?

       double z = 0;

       printf("%.2f", 1/z);

  28. The "1.#J" infinity is one of the other kinda after ROUNDING has occurred.

    I'm ashamed to admit it, but it took us years to realize that simple fact.

  29. nobugz says:

    Hehe, don't be ashamed.  There are not a lot of computer scientists that know what rounded infinity looks like.

Comments are closed.

Skip to main content