Separation in java

I have a simple section 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 is this happening?

+4
source share
4 answers

This is one of the most frequently asked questions in everything, so I put a couple of points here.

  • Computers can only represent a finite number of digits, so rounding should occur when storing numbers and their subsequent division. This rounding causes errors, naturally, but if you want, for example, 3 digits of accuracy, they should not matter in your case.

  • Rounding behavior is a little unpredictable as computers store numbers in binary format. Thus, while 19.7 is a finite decimal number, the same number is a repeating decimal in binary form - 10011.10110011001100110011001100110011 ...... so you can see that rounding at an arbitrary point will lead to behavior that is not predictable from the final decimal expression.

+2
source

The Mystic link is issued a must read, but it is a little thick. Try this site for a more beginner friendly version.

tl; dr - is that floating point arithmetic is always subject to rounding, and doubles, due to greater accuracy, will rotate differently than floats. This is a bit like 55 rounded to the nearest ten will be 60, but rounded to the nearest hundred will be 100.

In this case, you cannot represent the decimal number 0.197 (or 19.7, for that matter) exactly in both the floating point and double fields, so each one gives you a number that it can represent, which is closest to To this value, the Double can come a little closer, since it has great accuracy.

0
source

Not because of separation, the problem is that 1.7f! = 1.7 due to loss of accuracy. We can take a look at the bit representation 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 
0
source

Java uses the IEEE754 floating point number to process its float and double. This standard is for base base number 2, which cannot be used to accurately represent base 10. See here http://en.wikipedia.org/wiki/IEEE_floating_point .

The following is not a standard, but an example so that you understand why the base 2 floating point is not suitable for another 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. A 4-bit floating can only display base 10 numbers from 0 to 0.9325 with an interval of 0.0625. And this also means that he cannot do 0.1, 0.2, 0.3 ....

Since the actual standard uses a lot more bits, it also uses a digit switching method. It can indeed represent a much larger number than this example, but the restriction still remains the same. Therefore, when you divide a certain value, and the result does not fall on one of them ... the JVM will move it to the nearest one.

Hope this explains.

0
source

All Articles