Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how does Java convert floats to strings

Here's what I'm looking at:

float p=1.15f;
BigDecimal bdp=new BigDecimal(p);
float q=1.1499999f;
float r=1.14999999f;

System.out.println(p);   //1.15
System.out.println(bdp); //1.14999997615814208984375
System.out.println(q);   //1.1499999
System.out.println(r);   //1.15

So I understand that the decimal value of "p" 1.15 can't be represented exactly in binary.
And so the large big decimal "bdp" output makes perfect sense to me ... that's the actual value of the float.

Question 1
When the float "p" gets converted back to a string for output (as 1.15), how/where does that rounding occur (from the internal 1.149..375 value to 1.15)?

And where is it specified in the documentation? The toString javadoc doesn't really help (me at least).

I do see this in the language spec:

The elements of the types float and double are those values that can be represented using the IEEE 754 32-bit single-precision and 64-bit double-precision binary floating-point formats, respectively.

Wikipedia's IEEE 754 article gives this:

This gives from 6 to 9 significant decimal digits precision (if a decimal string with at most 6 significant decimal is converted to IEEE 754 single precision and then converted back to the same number of significant decimal, then the final string should match the original;

Question 2
So it seems that this is just how Java/IEEE 754 floats are supposed to work?

I get guaranteed accuracy of float/string conversion/representation up to a certain number of digits (like for "p" and "q"), and if that number of digits is exceeded Java will do some rounding for display (like for "r")?

Thanks for help.

like image 833
matt1616 Avatar asked Apr 30 '14 13:04

matt1616


Video Answer


1 Answers

I think this is the relevant part of the Javadoc that describes the behavior you're looking at (from the static String toString(float) method):

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.

To paraphrase: the toString methods for floating-point types will generally produce the shortest decimal representation that can unabmiguously identify the true value of the floating-point number.

Example program to illustrate:

import java.math.BigDecimal;

public class FloatTest {

  static void show(float f) {
    BigDecimal f_exact = new BigDecimal(f);
    System.out.println("---");
    System.out.println("String value: " + f);
    System.out.println("Exact value:  " + f_exact);
    System.out.println("Delta:        " + 
        new BigDecimal("1.15").subtract(f_exact));
  }

  public static void main(String[] args) {
    show(1.15f);
    show(Math.nextUp(1.15f));
  }
}

Output:

---
String value: 1.15
Exact value:  1.14999997615814208984375
Delta:        2.384185791015625E-8
---
String value: 1.1500001
Exact value:  1.150000095367431640625
Delta:        -9.5367431640625E-8
like image 92
Alex Avatar answered Sep 22 '22 23:09

Alex