Search code examples
javafloating-pointinfiniterepeat

why program can exactly display infinite repeating floating point number in java or other language


like a decimal number 0.1, represented as binary 0.00011001100110011...., this is a infinite repeating number. when I write code like this:

float f = 0.1f;

the program will rounding it as binary 0 01111011 1001 1001 1001 1001 1001 101, this is not original number 0.1. but when print this variable like this:

System.out.print(f);

I can get original number 0.1 rather than 0.100000001 or some other number. I think the program can't exactly represent "0.1", but it can display "0.1" exactly. How to do it?

I recover decimal number through add each bits of binary, it looks weird.

float f = (float) (Math.pow(2, -4) + Math.pow(2, -5) + Math.pow(2, -8) + Math.pow(2, -9) + Math.pow(2, -12) + Math.pow(2, -13) + Math.pow(2, -16) + Math.pow(2, -17) + Math.pow(2, -20) + Math.pow(2, -21) + Math.pow(2, -24) + Math.pow(2, -25));

float f2 = (float) Math.pow(2, -27);

System.out.println(f);

System.out.println(f2);

System.out.println(f + f2);

Output:

0.099999994

7.4505806E-9

0.1

in math, f1 + f2 = 0.100000001145... , not equals 0.1. Why the program would not get result like 0.100000001, I think it is more accurate.


Solution

  • Java's System.out.print prints just enough decimals that the resulting representation, if parsed as a double or float, converts to the original double or float value.

    This is a good idea because it means that in a sense, no information is lost in this kind of conversion to decimal. On the other hand, it can give an impression of exactness which, as you make clear in your question, is wrong.

    In other languages, you can print the exact decimal representation of the float or double being considered:

    #include <stdio.h>
    
    int main(){
      printf("%.60f", 0.1);
    }
    

    result: 0.100000000000000005551115123125782702118158340454101562500000

    In Java, in order to emulate the above behavior, you need to convert the float or double to BigDecimal (this conversion is exact) and then print the BigDecimal with enough digits. Java's attitude to floating-point-to-string-representing-a-decimal conversion is pervasive, so that even System.out.format is affected. The linked Java program, the important line of which is System.out.format("%.60f\n", 0.1);, shows 0.100000000000000000000000000000000000000000000000000000000000, although the value of 0.1d is not 0.10000000000000000000…, and a Java programmer could have been excused for expecting the same output as the C program.

    To convert a double to a string that represents the exact value of the double, consider the hexadecimal format, that Java supports for literals and for printing.