15

As everybody knows, you have limited precision when you use printf to output the value of a float.
However, there is a trick to increase the accuracy in the output, as this example shows:

#include <stdio.h>

int main()
{
    float f = 1318926965;        /* 10 random digits */
    printf("%10.f\n", f);        /* prints only 8 correct digits */
    printf("%10d\n", *(int*)&f); /* prints all digits correctly */
    return 0;
}

and my question is, why don't people use this trick more often?

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
  • 1
    Because potentially undefined behavior is bad. (Edit: Technically it may not be undefined behavior, as I'm not sure what the standard says about it. Endianess could bite you with this though.) – Corbin Apr 01 '12 at 08:53
  • 9
    +1 for a good April's 1st joke! – Henrik Apr 01 '12 at 09:03
  • It apparently got me x.x – Corbin Apr 01 '12 at 09:16
  • 1
    You should have used an union for an irreproachable April's fool joke. – Pascal Cuoq Apr 01 '12 at 09:33
  • Or some macro that makes it totally unclear what I'm doing? No, I didn't want to obfuscate my program. Sometimes it's best to hide things out in the open. – Mr Lister Apr 01 '12 at 09:38
  • 1
    @MrLister I'm not saying that your program is too readable, I am saying that it is too undefined. Look up "strict aliasing rules" tomorrow. – Pascal Cuoq Apr 01 '12 at 12:17

3 Answers3

11

April fool?

Your "random number" 1318926965 have the same underlying representation both in decimal and floating-point form.

Try another value, like 10. It will print as:

        10
1092616192

So to answer your question:

and my question is, why don't people use this trick more often?

Because only one day of the year is April Fools Day... The rest of the days the trick doesn't work...

Lindydancer
  • 25,428
  • 4
  • 49
  • 68
4

Try that same trick with a different number, say 2318926965.

#include <stdio.h>

int main()
{
    float f = 2318926965;        /* 10 random digits */
    printf("%10.f\n", f);        /* prints only 8 correct digits */
    printf("%10d\n", *(int*)&f); /* prints all digits correctly */
    return 0;
}
$ gcc -Wall -O3  t.c
t.c: In function ‘main’:
t.c:7:5: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
$ ./a.out 
2318926848
1326069764

I don't see an increase in precision at all with your "trick" that depends on the bit representation of floats on your platform (as far as I understand it).

This thread has a few other of these "magic floats" and a way to generate them.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • It depends on the bit representation of floats per IEEE 754, not "on your platform". (Modulo possible byte order issues that don't exist on any real-world machines.) IMO the only thing bad about code like this is the improper type-punning which should be replaced with unions (sketchy but intentionally supported by all compilers) or `memcpy` (100% legal C). – R.. GitHub STOP HELPING ICE Apr 01 '12 at 13:55
  • If IEEE 754 is mandatory, what's the use for the `__STDC_IEC_559__` define? – Mat Apr 01 '12 at 14:09
  • It's not mandatory, but considering how broken the C standard allows non-IEEE-conformant implementations' floating point to be, and that there's no other way you can tell what you can rely on in regards to floating point arithmetic, I would consider it a huge mistake for programs that want to be portable to non-IEEE-math systems to use floating point whatsoever. (Naturally however you could use it on a non-portable program intended only for use on a single non-IEEE-math implementation.) – R.. GitHub STOP HELPING ICE Apr 01 '12 at 14:15
  • Thanks for the interesting link! – ysap May 20 '14 at 18:54
0

The limit to precision is with the floating point representation, not with printf() it is a false premise.

Moreover a single precision float is only guaranteed correct to 6 digits of precision, so the "trick" would be fooling yourself; in the general case it would not work.

If you want 10 digit floating-point numbers then you should use double precision, which is good for 15 digits.

Clifford
  • 88,407
  • 13
  • 85
  • 165