简体   繁体   中英

java - float precision when output in console

float x = 0.98123452f;
System.out.println(x); //it prints out 0.9812345

float x = 0.98123453f;
System.out.println(x); //it prints out 0.98123455

I have no idea why the second one's output is 0.98123455 instead of 0.9812345. Isn't the precision of float is 7 decimal digits?

To see the exact value of your float, you can use a BigDecimal:

 
 
 
  
  float x = 0.98123452f; System.out.println(new BigDecimal(x));
 
  

which outputs: 0.981234490871429443359375

So technically, this float:

 
 
 
  
  float x = 0.981234490871429443359375f; System.out.println(new BigDecimal(x)); //prints 0.981234490871429443359375
 
  

has 24 digits precision (it was obviously cherry-picked)...

Forget what is above: BigDecimal only has a double constructor so there was a cast to double and the logic above is flawed.

Bottom line: not all numbers can be represented as a float and the gap between one float and the next one varies depending on the magnitude of the number.

The IEEE 754 float representation of

0.98123453 

is 32 bits of (sign, exp, mantissa):

0 01111110 11110110011001000110000

which is:

0.9812345504760742

in double precision, and cast back to float decimal representation:

 0.98123455

The number of bits allocated to a single precision (float) is 32, and 64 bits for double precision. Further note that BigDecimal that is frequently suggested will store your number as a string, and not in IEEE754 format. It will do a conversion when it needs to act on the number, and while it has a better precision, it is awfully slow.

EDIT. To clarify why it prints 0.98123455, we need to observe that it is the closest single precision representation of the number 0.98123453:

00111111011110110011001000101111 = 0.9812345  (sp) = 0.9812344908714294 (dp)
00111111011110110011001000110000 = 0.98123455 (sp) = 0.9812345504760742 (dp)
00111111011110110011001000110001 = 0.9812346  (sp) = 0.981234610080719  (dp)

sp = single precision, dp = double precision

The listing is for the [-1,+1] binary range around the number, and you can see that 0.98123453 is closest to the 10000 suffix of the mantissa, while 0.98123452 is closest to the 01111 suffix.

isn't the precision of float is 7 decimal digits?

No. It is 23 binary digits. The minimum number of decimal digits that can be represented in 23 bits is therefore 6. This is not a mere 'guarantee' as stated in other answers here, it is a mathematical tautology arising from log10(2^23) = 6.92369.

The default output format for floating-point in Java is to print just enough digits so that conversion back to the floating-point type produces the original value.

What happens in detail in your code is:

  • The source text 0.98123452f is converted to the float value 0.981234490871429443359375.
  • This is printed as “0.9812345” because that is just enough digits. The nearest float value to 0.9812345 is 0.981234490871429443359375. However, converting “0.981234” to float would produce 0.981234014034271240234375, so the “5” is needed.
  • The source text 0.98123453f is converted to the float value 0.98123455047607421875.
  • This is printed as “0.98123455” because that is just enough digits.

An interesting consequence of this is that, if you assign a float value to a double object and then print the double value, it will often display more digits than printing the float value, even though the values are exactly the same. Because the double format is finer (more precise) than the float format, there may be many double values between the value printed for float (eg 0.9812345) and the actual value (0.981234490871429443359375). Therefore, more digits are needed to distinguish the value.

不, float只有六位数的十进制精度。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM