What does 1#J mean? A strange corner case of the printing of special values

As a puzzle, commenter nobugz asks, "What kind of infinity is 1.#J?"

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

Now, the division by zero results in IEEE positive infinity, would would normally be printed as 1#INF. But the catch here is that the print format says "Display at most two places after the decimal point." But where is the decimal point in infinity?

The Visual C runtime library arbitrarily decided that all of the exceptional values have one digit before the decimal (namely, the "1"). Actually, it turns out that this puzzle might be an answer to Random832's question, "What's the 1 for?" Maybe the 1 is there so that there is a digit at all.

Okay, so now you have one digit before the decimal (the "1"), and now you need to show at most two places after the decimal. But "#INF" is too long to fit into two characters. The C runtime then says, "Well, then I'd better round it off to two places, then."

The first character is "#". The second character is "I". Now we need to round it. That's done by inspecting the third character, which is "N". We all learned in grade school that you round up if the next digit is 5 or greater. And it so happens that the code point for "N" is numerically higher than the code point for "5", so the value is rounded up by incrementing the previous digit. Incrementing "I" gives you "J".

That's why printing IEEE positive infinity to two places gives you the strange-looking "1#J". The J is an I that got rounded up.

I doubt this behavior was intended; it's just a consequence of taking a rounding algorithm intended for digits and applying it to non-digits.

Of course, in phonetics, rounding an i produces a ü. Imagine the nerdiness of rounding "1#INF" to two places and producing "1#Ü". That would have been awesome.

Comments (44)
  1. Kujo says:

    Hah, and so "0.1f" would produce "1.$" and "0.3f" would produce "1.#IO".  Excellent.  I just love that there can still be corner cases to printf/scanf that I haven't encountered yet.

  2. Or if you have Unicode, just go right for ∞

  3. AC says:

    The second character is "I". Now we need to round it. That's done by inspecting the third character, which is "N".

    At this point I was already thinking: "ROT13 of A is N, so N is in the second half of the alphabet and get's rounded up. Wait, WTF?!?"

    The given explanation thankfully makes a lot more sense than that.

  4. Jim says:

    Very interesting, I wonder how he figured those useless details out??

  5. AsmGuru62 says:

    @Jim: probably by disassembling the VC RTL.

    [No need to disassemble. Visual Studio includes the source code to the C Runtime Library. -Raymond]
  6. @AC I had the same initial thought… A-M round down, N-Z round up

  7. Igor Tandetnik says:

    For what it's worth, the C99 standard (I don't have a copy of C90 handy) explicitly prescribes how printf() should output infinite and NaN values: …A double argument representing an infinity is converted in one of the styles [-]inf or [-]infinity — which style is implementation-defined. 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 produces INF, INFINITY, or NAN instead of inf, infinity, or nan, respectively.234)

    Footnote 234) When applied to infinite and NaN values, the -, +, and space flag characters have their usual meaning; the # and 0 flag characters have no effect.

    MSVC is non-conforming in this regard.

  8. mikeb says:


    Unfortunately, MSVC doesn't claim conformance with C99.  C90 doesn't seem to say what should be output when the argument represents an infinity.

  9. Andrew says:

    Thank you for the last paragraph.  Just thank you.

  10. j b says:

    Funny observation: This wouldn't happen in Norway…

    Norwegian (like other Scandinavian languages) adds three extra letters (Æ, Ø Å) at the end of the alphabet, so the middle character is 'O' (which is easy to remember, as it looks the same from both sides…), and 'N' is in the lower half.

    This obviously assumes that the rounding is bsed on the character number in the alphabet, counting from 'A' to the last character ('Å'  in the Norwegian alphabet).

  11. mikeb says:

    > and 'N' is in the lower half.

    but it's still greater than '5'.

  12. CherryDT says:

    @j b: 5 has ASCII code 53 while N has ASCII code 78, so N is always greater than 5.

  13. Lars says:

    Actually, the sign for a rounded [i] is not [ü], but [y] (in the International Phonetic Alphabet, which is what you'd be using when discussing phonetics /per se/, not the study of a particular language where things may be different). But then, you'd have to invent a way of getting the brackets into place (because without them, you shouldn't parse i as a phonetic entity at all – that would be considered a bug).

  14. Is this another but that's doomed to be in windows forever for "compatibility reasons"?

  15. Cesar says:

    @Rosyna: probably not. Every new version of MSVC has a new separate copy of the C runtime with a different name (unlike on most Unix systems, where there is a single C runtime shared by all compilers – yet another cause of pain when porting software for Windows). So a new version of MSVC could fix all these bugs, without risking breaking anything, since only new applications would link to the new C runtime.

    [The flip side is that these sorts of subtle behavioral changes may prevent people from upgrading to MSVC version N+1. "We upgraded to MSVC version N+1 and our reports don't print properly (because a change in output format caused one of the output lines to go longer than 80 characters, which messed up the columns, and a downstream consumer couldn't parse it correctly)." (Also, does Unix really have more than one C compiler?) -Raymond]
  16. AndyCadley says:

    @Cesar: The world of compatibility is never that easy, alas, as anyone reading this blog already knows. An existing C codebase being compiled in a new version of Visual Studio would subtly change behaviour if the C runtime changed and that leads to all manner of potentially exciting new bugs in code that's already been long tested. At this point the cost of "fixing" the behaviour to C99 conformance may well be higher than the benefits gained from compliance. Increasingly so as less and less new application development is done in C.

  17. Daniel Neely says:

    "Also, does Unix really have more than one C compiler?"

    IIRC The Solaris shell I used as a student a dozenish years ago had two.  gcc and cc; the latter I assume was Sun's proprietary version.  On newer systems you can use clang+llvm instead of gcc.  If only for legacy support I wouldn't be surprised if the few lingering proprietary unixes still provide their legacy compilers even if they're no longer under active development.

  18. Daniel Neely says:

    This makes me wonder what competing pre-C99 compilers output.

  19. Evan says:

    "Also, does Unix really have more than one C compiler?"

    GCC is pretty darn dominant, but as Daniel says, there are others.

    With some regularity I use GCC, Intel's, and Clang. At one point or another I've also used Sun's (I'm not sure I have access to a Sun machine any more) as well as Pathscale's. Apparently I also have access to the Portland Group compilers… but I am not sure I've ever used them.

    "This makes me wonder what competing pre-C99 compilers output."

    I tried GCC 2.95 (1999), but it just picks up the modern libc. (I wish that Sparc machine were up… I've got 2.7 that'll run on that and Alpha. :-))

  20. But you don't have any proof that someone will run into this problem. Yet the bug still won't be addressed. It'll just always be there with a note somewhere saying "1#J" Means "infinite".

    What does printf do in the Visual C runtime if the answer is NaN?

    [And you have no proof that someone won't run into this problem. I've seen apps break for much less significant change than this. I mean, we're changing the length of a string. Lots of Web sits broke because the IE user agent string got one character longer ("MSIE9" to "MSIE10"). -Raymond]
  21. It's a moot point. Microsoft has publicly stated they will never support anything newer than C90 in Visual Studio (http://www.infoq.com/…/vs_c99_support). So that's a dead-end. From that statement it seems like there has never been a MSVC+1 since C90 support was added. It seems @Cesar's comment was on the money. VS ships a C compiler with a C runtime that's trapped in time.

  22. CherryDT says:

    What does printf do in the Visual C runtime if the answer is NaN?

    Didn't test it, but I assume it would be:











  23. JustSomeGuy says:

    It's only a bug if it's wrong (and it isn't). Since MS have stated they're not attempting full C99 compliance, and ISO C90 does not specify what gets printed for these out-of-bound values, MS can pretty much do whatever it wants.

    In any case MS DON'T ship a C compiler, they ship a C++ compiler that happens to compile C code. If you want compliance with the latest and greatest C, use gcc et al.

  24. Artem S. Tashkinov says:


    This post will be 100% off topic but since your are on a Windows development team I thought I would let you know.

    We have discovered that the "turn off windows write-cache buffer flushing on the device" option (enabled) causes data loss on reboot when installing Windows updates. We had at least four incidents when our PCs became unbootable since crucial Windows files were wiped out on reboot.

    I wonder if your team could investigate this issue and release a fix for it.

    Thank you.

    [Dangerous setting is dangerous. -Raymond]
  25. A. Skrobov says:

    In the older post, you say: "Positive and negative infinity are generated .. when the mathematical result of an operation is infinite, such as taking the logarithm of positive zero."

    In fact, x86 returns -1.#INF as the logarithm of negative zero, too. Only non-zero negative values result in a -1.#IND.

  26. GP says:

    Hello Artem,

    so you think Raimond will investigate, and release a "fix" for it. Maybe he'll send it to you by mail ;-). This blog is no alternative to Product Support Services!

    BTW: By checking the specified option, you allow Windows NOT to flush data. So everything ok here!

    [Flushing your performance down the drain, that is – The Old New Thing – Site Home – MSDN Blogs]


    "To prevent data loss, do not select this check box unless the device has a separate power supply that allows the device to flush its buffer in case of power failure."


  27. Ooh says:

    @Artem S. Tashkinov: You asked for trouble, you got trouble. Where's the problem? It's NOT a bug since the product behaves exactly how it should and is documented.

  28. Carry ? says:

    One thing I don't get is why it doesn't get to 2#0 or other dumb value, since "I" is also greater than "9" in ASCII and the carry logic should somehow trigger and provide an even dumber print (just like 1.995 would get you "2.00" and not "1.9:"). Where am I wrong ?

  29. CherryDT says:

    Maybe the logic says basically while(character[i] == ':') {character[i] = '0'; character[i–]++;} so everything else except rounding 9 to 0 instead of : is not handled…?

  30. Allan Peda says:

    With the increasing pervasiveness of Unicode, is it possible now to use the Infinity symbol ( ∞) instead of "INF:, sidestepping much of this oddness?

  31. Random832 says:

    [No need to disassemble. Visual Studio includes the source code to the C Runtime Library. -Raymond]

    I looked when you posted the last article – It includes the source to most of the C Runtime Library, but if it includes the source to _cfltcvt (which appears to be where the meat is, based on looking at _output) at all, I couldn't locate it. I had assumed parts of the library relating to floating point couldn't be distributed because they weren't owned by Microsoft or something.

    [You're right. I don't know why they left out the floating point stuff. -Raymond]
  32. Random832 says:

    The only way to change this while maintaining compatibility is to do something like symbol versioning – the function used in "C99 mode" (or C++1x mode) maps to a different function in the DLL than the one used in other modes, and choosing between them has to be handled by the compiler. Something like this is done by glibc, but it doesn't support building new apps using the old versions of functions (at least, not without doing something exotic with a linker script, or using the old library at link time), and it's exactly as much of a mess as it sounds like.

    @Allan Peda – no. If you want to do it, you can write your own formatting function, but there's no good reason to put it in printf and many good reasons not to.

  33. CherryDT says:

    Correction of my post before: –i, not i–

  34. Jeff says:

    When I round up infinity I get ∟ (right angle character). So now we know what comes after infinity! Angles!

  35. @Jeff: when I round up infinity I get infinity.

  36. CarlD says:

    [You're right. I don't know why they left out the floating point stuff. -Raymond]

    From my years as a C++ MVP, I believe it's because that code (and most/all of the lowest-level FP code) is licensed from another entity under terms that don't give MSFT the right to redistribute the source code.

  37. Adam Rosenfield says:

    Although Visual Studio is likely to never support C99, I'm hopeful that they may decide to support C11.  C11 makes optional some of the mandatory parts of C99 which are difficult to implement (namely variable-length arrays).  I think it's still unlikely, but I can always hope…

  38. mikeb says:

    > In any case MS DON'T ship a C compiler, they ship a C++ compiler that happens to compile C code.

    So a compiler that compiles C code isn't a C compiler?

  39. Doug says:

    @Jeff: An angle past infinity?  Perhaps some kind of non-Euclidean geometry where the angle is acute but behaves as if it were obtuse?  Possibly insidiously curious enough to drive a man mad?

  40. mikeb says:

    So now we know what comes after infinity! Angles!

    It's angles all the way down!

  41. Infinity plus -e^jπ. - Doh! says:

    I personally like #J. J is one better than I.

  42. So a compiler that compiles C code isn't a C compiler?

    A compiler that compiles all kinds of C code is an ideal C compiler.

    A compiler that compiles almost all kinds of C code, most of the time, with the occasional bug, is a real C compiler.

    A compiler that compiles a fair amount of C code, with significant chunks of standards support missing, and no plans to add them, begins to not be a C compiler anymore.

  43. 640k says:

    The ∞ character has been in DOS character table since day 1, there's NO excuse to not use it.

    It has also always been in the ANSI table. A compiler which can only compile windows binaries should of course use characters which exist in the OS for which it compiles binaries. I suppose the compiler guys didn't like the OS they developed the compiler for.

  44. ErikF says:

    @640k: Which ANSI table would that be? True, it's in the IBM-437 codepage but I don't see the infinity symbol in the 850 Latin-1 codepage (or the 720 Arabic, or 737 Greek, or 855 Cyrillic, etc.) Sticking with ASCII seems like a better option if you're not in a position where you can assume anything about the character set that a program is using; it covers basically every case except for EBCDIC and a few other odd cases.

Comments are closed.