12

I've read a lot about float representation recently (including this: How To Represent 0.1 In Floating Point Arithmetic And Decimal). Now I understand that 0.1 can't be represented correctly, and when I do this:

System.out.println(2.0f - 1.9f);

I'll never get precise result.

So the question is: How represented 0.1f in the following code in order to print 0.1 correctly? Is that some kind of syntatic sugar? In the article that I above mentioned says: 0.1 represented in memory as 0.100000001490116119384765625. So why I don't get this output for this code:

System.out.println(0.1f);

How does Java deal with this?

Community
  • 1
  • 1
Balazs Varhegyi
  • 991
  • 1
  • 18
  • 37

2 Answers2

18

System.out.println performs some rounding for floats and doubles. It uses Float.toString(), which itself (in the oraclew JDK) delegates to the FloatingDecimal class - you can have a look at the source of FloatingDecimal#toJavaFormatString() for gory details.

If you try:

BigDecimal bd = new BigDecimal(0.1f);
System.out.println(bd);

You will see the real value of 0.1f: 0.100000001490116119384765625.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • Wow, what a speed! Thanks very much! – Balazs Varhegyi Aug 26 '12 at 09:11
  • 3
    You don't need to look at the source at all - you can just look at the documentation of `Float.toString(float)` which gives a very clear reason why `Float.toString(0.1f)` will return "0.1". – Jon Skeet Aug 26 '12 at 09:11
  • @JonSkeet I meant that he could have a look at the source to see how it's done, not why - you addressed the why in your answer. – assylias Aug 26 '12 at 11:30
  • But the expression is evaluated before it's passed to `System.println`. If there are different results, it can only be because the expressions resolve to different values. So why is the result of the expression `2.0f - 1.9f` somehow different from the expression `0.1f`? – Michael Aug 22 '18 at 16:34
  • 1
    @Michael because `2.0f - 1.9f != 0.1f`. See their exact values here: https://ideone.com/VCR3wJ – assylias Aug 22 '18 at 17:10
6

From the docs for Float.toString(float) (which will always give the same results as the string you're printing):

How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type float.

As 0.1f is the closest representable float to the exact value 0.1, it makes sense that no more digits are required to uniquely distinguish that from any other value of the float type.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    It should be noted that the implementation doesn't correctly implement the javadoc in all cases; see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7019078, http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7021568 and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5007445 (about printf, so not the same javadoc ...). However, that's not the problem here. – Stephen C Aug 26 '12 at 10:30