3

According to several floating point calculators and as well as my code below, the following 32 bits 00111111010000000100000110001001 has an actual Floating Point value of (0.750999987125396728515625). Since it is the actual Float value, I should think storing it in a Double or Float would retain the precision and exact value so long as (1) no arithmetic is performed (2) the actual value is used and (3) the value is not down-casted. So why is the actual value different from the casted (example 1) and literal (example 2) value of (0.7509999871253967)?

I used this calculator as an example: https://www.h-schmidt.net/FloatConverter/IEEE754.html

enter image description here

import java.math.BigInteger;
import java.math.BigDecimal;

public class MyClass {
    public static void main(String args[]) {
      int myInteger = new BigInteger("00111111010000000100000110001001", 2).intValue();
      Double myDouble = (double) Float.intBitsToFloat(myInteger);
      String myBidDecimal = new BigDecimal(myDouble).toPlainString();

      System.out.println("      bits converted to integer: 00111111010000000100000110001001 = " + myInteger);
      System.out.println("    integer converted to double: " + myDouble);
      System.out.println(" double converted to BigDecimal: " + myBidDecimal);

      Double myDouble2 = 0.750999987125396728515625;
      String myBidDecimal2 = new BigDecimal(myDouble2).toPlainString();

      System.out.println("");
      System.out.println("       Ignore the binary string: ");
      System.out.println("            double from literal: " + myDouble2);
      System.out.println(" double converted to BigDecimal: " + myBidDecimal2);
    }
}

Here is the output:

      bits converted to integer: 00111111010000000100000110001001 = 1061175689
    integer converted to double: 0.7509999871253967
 double converted to BigDecimal: 0.750999987125396728515625

       Ignore the binary string: 
            double from literal: 0.7509999871253967
 double converted to BigDecimal: 0.750999987125396728515625
poetryrocksalot
  • 697
  • 2
  • 10
  • 19
  • 1
    Why do you think the value isn't preserved? Is it that you expect the line `"integer converted to double`" to give you 0.750999987125396728515625? – Louis Wasserman Jun 05 '20 at 22:14
  • Yes, I do expect it. Perhaps precision is loss during calculation. Furthermore I expect the literal (example 2) to print out the full value since it is a literal representation that matches the actual value for 32-bits. – poetryrocksalot Jun 05 '20 at 22:24

1 Answers1

7

There is no actual loss of precision; the issue is your incorrect expectations about how doubles are converted to String (e.g. when printed).

From the documentation of Double.toString:

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 double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.

So when a double gets printed, it is printed only with enough digits to uniquely identify that double value, not with the number of digits needed to describe the precise value as a real number.

If you want to get the precise value of a double with all possible digits, new BigDecimal(theDouble).toPlainString() is how you do it -- and, as you demonstrate, it gets the correct result.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • I bet it is related to the double's precision guarantee of no more than 16 digits to the right of the dot. The unique identification makes sense because after the 16th digit, variations of the 17th digit could result in the same bit representation. Am I getting this right? – poetryrocksalot Jun 05 '20 at 22:38
  • 1
    The precision guarantee isn't really about decimal digits, but binary digits, but that's the idea. – Louis Wasserman Jun 05 '20 at 22:45
  • 2
    @poetryrocksalot A `double` decimal precision wobbles between 15 and 17 significant decimal digits per power of 10. The binary precision is 53 significant binary digits over a given power of 2. – chux - Reinstate Monica Jun 06 '20 at 00:02