简体   繁体   中英

Performing repeated additions on float or double values produces unexpected results

I found a but in my code and after some searching I realized that some floating operations that I was performing produced the wrong results. So I typed the following loop:

 float f = 0f;
     for(int i =0; i<15; i++){
        f+= 10.1f;
        System.out.println(f);
}

But in the results I get unexpected additional decimal values:

10.1
20.2
30.300001
40.4
50.5
60.6
70.7
80.799995
90.899994
100.99999
111.09999
121.19999
131.29999
141.4
151.5

What is going on here and how do I prevent it?

You can't "prevent" it. What you need to do instead is expect it and compensate.

See: What Every Computer Scientist Should Know About Floating-Point Arithmetic

The numbers are stored as binary, and at a certain precision the representation between binary and decimal is not perfect, essentially leading to 'rounding errors'. If precision is of importance in this scenario, try using BigDecimal instead

Two operations in your code cause errors:

  • The conversion of the source text 10.1f to float . This conversion is inexact because 10.1 cannot be exactly represented in the floating-point format Java uses.
  • The additions of 10.1f to previous values of f . In many of these additions, the exact sum will not fit completely in the floating-point format, so the result must be rounded.

You can modify the loop to avoid accumulating errors:

for (int i = 0; i < 15; i++)
{
    f = (i+1) * 101 / 10.f;
    System.out.println(f);
}

When you write the code in this way, f will still not be exactly 10.1•( i +1) in every iteration, but it will be the closest representable value. In this new version, (i+1) * 101 is calculated exactly, and 10.f is exactly 10 because 10 is representable in the floating-point format. This means that the only error is in the division operation. That operation will return the representable value closest to the exact result.

Java uses IEEE-754 binary floating-point, 32 bits for float and 64 bits for double . In those formats, a number is represented, basically, as an integer times a power of 2. In the 32-bit format, the integer must have magnitude less than 2 24 . The closest you can get to 10.1 in the 32-bit format is 5295309•2 -19 , which is 10.1000003814697265625.

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