There and back again: riddle for floating-point numbers (almost no tricks)

Few days ago I saw that and thought, that it could be interesting. Nothing complex, special, mostly well-known knowledge, just an unusual angle.

The riddle: You have a simple program in C/C++ that write a floating-point (double) number into a file, and then reads it from there using simple printf and scanf. There is nothing else in this file. As an example, the function below does the same with a simple string buffer instead of a file:

void qu(double g)
{
char buf[2000];
sprintf(buf,"%lf\n", g);
fputs(buf,stdout);
double q = 0;
int n = sscanf(buf,"%lf",&q);
printf("Got back %d numbers = %lf\n\n", n, q);
}

The question: will it always work? Will you always get what you put inside (putting aside evident rounding for text representation)?

-------------------- the answer (gray on gray, select to see the text) ----------------

Nope. IEEE standard for floating-point numbers defines a couple of unusual numbers like ±infinity of ±Not-a-Number (nan). Here is an example of calling the function above that will read different values than those, you tried to print:

#include <windows.h>
#include <stdio.h>

int wmain(int argc, WCHAR* argv[])
{
float f0 = 0;
unsigned long nan[2]={0xffffffff, 0x7fffffff};
double g = *( double* )nan;
qu(g);

 nan[1] = 0xffffffff;
g = *( double* )nan;
qu(g);

 g = 5.0/f0;
qu(g);

 g = -5.0/f0;
qu(g);

 return 0;
}

And the output from this code will look like:

1.#QNAN0 1.#QNAN0e+000
Got back 1 numbers = 1.000000

-1.#QNAN0 -1.#QNAN0e+000
Got back 1 numbers = -1.000000

1.#INF00 1.#INF00e+000
Got back 1 numbers = 1.000000

-1.#INF00 -1.#INF00e+000
Got back 1 numbers = -1.000000

The problem is that scanf() does not recognize some of the output formats created by printf(). “1.#QNAM0” it considers to be “1.” and some text data afterward.

------------------------ end of the answer -------------------