4

I have a simple division in Java:

float f = 19.7f/100;
System.out.println(f); // 0.19700001

double d = 19.7/100;
System.out.println(d); // 0.19699999999999998

Why does this happen?

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
user2126055
  • 41
  • 1
  • 2
  • 7
    http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – Mysticial Mar 02 '13 at 06:59
  • `0.19700001` is a conversion to decimal of the nearest single-precision floating-point approximation of 0.197. On the other hand, `0.19699999999999998` is a conversion to decimal of the nearest double-precision floating-point approximation of 0.197. Java is doing exactly what you asked it by using and not using the `f` suffix. See http://blog.frama-c.com/index.php?post/2011/11/08/Floating-point-quiz for more examples (in C, but the issue is the same). – Pascal Cuoq Mar 02 '13 at 09:16

4 Answers4

3

This is one of the most commonly asked questions in anything ever, so I'll put a couple of points down here.

  1. Computers can only represent a finite number of digits, so rounding off has to occur when storing numbers and later dividing them. This rounding off produces errors naturally, but if you only want, say, 3 digits of precision, they shouldn't matter in your case.

  2. The behavior of rounding off is a bit unpredictable because computers store numbers in binary. So whereas 19.7 is a terminating decimal, the same number is a repeating decimal in binary -- 10011.10110011001100110011001100110011... ... so you can see that rounding off at an arbitrary point will produce behavior that is not predictable from the terminating decimal expression.

Justin L.
  • 13,510
  • 5
  • 48
  • 83
0

The link Mystical gave out is a must-read, but it's a bit thick. Try this site for a more beginning-friendly version.

The tl;dr is that floating point arithmetic is always subject to rounding, and doubles, by virtue of having more precision, will round differently than floats will. It's a bit like how 55 rounded to the nearest ten will be 60, but rounded to the nearest hundred will be 100.

In this case, you can't represent the decimal number 0.197 (or 19.7, for that matter) exactly in either a float or a double, so each one gives you the number that it can represent which is closest to that value. The double can get a bit closer, since it has more precision.

yshavit
  • 42,327
  • 7
  • 87
  • 124
0

It is not because of the division, the problem is that 1.7f != 1.7 due to precision loss. We can take a look at the bit representations of our values

    float f = 19.7f; 
    double d = 19.7;
    System.out.println(Double.doubleToLongBits(f)); 
    System.out.println(Double.doubleToLongBits(d));

output

4626238274938077184
4626238274723328819
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
0

Java uses IEEE754 Floating point number to handle its float and double. This standard is designed to ise base 2 number which can't be used to represent base 10 accurately. See here http://en.wikipedia.org/wiki/IEEE_floating_point .

The following is not exactly the standard but an example just to get you some idea why base 2 floating point is not suitable for other base.

base2  = base10
 0001  = 0001   -> from 0*8 + 0*4 + 0*2 + 1*1
 0010  = 0002   -> from 0*8 + 0*4 + 1*2 + 0*1
 0011  = 0003   -> from 0*8 + 0*4 + 1*2 + 1*1
 0100  = 0004   -> from 0*8 + 1*4 + 0*2 + 0*1
 0101  = 0005   -> from 0*8 + 1*4 + 0*2 + 1*1
                   8 = 2^3, 4 = 2^2, 2=2^1 and 1 = 2^0

Then
base2   = base10
 .0000 = .0000  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0001 = .0625  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0010 = .1250  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0011 = .1875  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0100 = .2500  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0101 = .3125  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0110 = .3750  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0111 = .4375  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1000 = .5000  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1001 = .5625  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1010 = .6250  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1011 = .6875  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1100 = .7500  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1101 = .8125  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1110 = .8700  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1111 = .9325  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0

                   1 = 2^0, 0.5 = 2^-1, 0.25=2^-2 and 0.125 = 2^-3

As you can see. 4 bit floating can only represent base 10 numbers from 0 to 0.9325 with the gap of 0.0625. And that also means it can't do 0.1, 0.2, 0.3 ....

Since the actual standard use many more bit as well as using digit shift technique. It can really represent many more number than this example but the limitation still the same. So when you divide some value and the result does not fall on one of these ... JVM will move it to the closest one.

Hope this explain.

NawaMan
  • 25,129
  • 10
  • 51
  • 77