0
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?

2
  • 2
    Not really, nor any other number of decimal digits. It has 23(+1) bits of precision. The decimal representation is highly misleading. Commented Feb 8, 2014 at 9:31
  • The console has precisely nothing to do with it. Commented Feb 8, 2014 at 9:32

5 Answers 5

2

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 (e.g. 0.9812345) and the actual value (0.981234490871429443359375). Therefore, more digits are needed to distinguish the value.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

2 Comments

why it output 8 decimal digits instead of 7?
Because the double precision of 0.98123452 is 0.9812344908... which is truncated to 0.9812345 for printing. So you should the question the other way around - why is it outputting 7 instead of 8.
0

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.

1 Comment

The significand of an IEEE-754 32-bit binary floating-point object has 24 bits, not 23. 23 are encoded in the significand field, one is encoded via the exponent field.
0

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.

5 Comments

Well that's because BigDecimal precision isn't IEEE-754 precision. It stores the number as a string.
@mockinterface Where I made a mistake is that there is no constructor taking a float, so x is actually cast to a double. However "When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion", according to the javadoc.
Sure, that just means that it won't convert the double to a string first to forward to the string constructor, preventing you from losing precision even further.
Actually, every float can be represented by a double exactly. And in turn every double can be represented as a decimal fraction exactly. So the 0.981234490871429443359375 you get is really the mathematically exact value of the float x. This does not mean the accuracy is 24 digits, the value differs from the intended one already in the seventh place.
@mockinterface BigDecimal does not store the number as a string, and it has 16 constructors, from all sorts of data types.
-1

No, float has just six digits of decimal precision.

2 Comments

I believe it can be more than 6 digits in some cases (but at least 6 in all cases).
6–9, indeed. but six is the guaranteed number.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.