Phenomenon of the problem

:

I was asked this question and the picture is below.

The question a lot of people have is that the result of the program is 9, shouldn’t it be 8? We can run a line like this in our program

[Java]

Plain text view
Copy the code

?
System.out.println(
0.1
+
0.7
);

The result of the program is 0.79999999999999. This number is obviously less than 0.8, so we have the result shown above. So why does this happen?


Problem principle


In fact, many floating point numbers in computers are themselves approximations because they cannot be accurately represented. This comes from the fact that the underlying computer is binary, such as 0.1. Why can’t 0.1 be expressed exactly? It’s accurate in the decimal world, but not in binary. Let’s take an example. So 78.912, for example, looks like this.

7 * 10 + 8 + 9 * 0.1 * 1 + 1 + 2 * 0.01 * 0.001

And each of the decimal places also has a weight. If we switch to scientific notation, then

10 ^ 7 * 1 + 8 * 10 * 10 ^ ^ 0 + 9 (1) + 1 * 10 ^ (2) + 2 * 10 ^ (3)
.

Although most of them can be accurately represented in base 10, many of them can’t be accurately represented in binary. For example, 10/3 is approximately 3.33, no matter how many decimal places there are, 10/3 can’t be accurately represented, only approximately 3.33. In fact, binary is similar, binary decimal notation in scientific notation, first look at 2 to the x power corresponding to the base 10 data.
So we can understand the decimal value 0.1 = 1*2^(-?). + 1 * 2 ^ (-)? + 1 * 2 ^ (-)? +… No matter how you add them up, you end up getting infinitely close to 0.1, not really 0.1. One might ask that the program does display 0.1, which is an illusion given by the Java language, and that the calculation is actually inaccurate, but because the result is close enough to 0.1, Java chose to print 0.1, which looks like a very compact number, rather than a decimal with lots of zeros in between. When the error is small enough, the result looks accurate, but inaccuracy is the norm. Binary represents decimal, also uses the scientific calculation method, such as m*(2^e). M is called the mantissa and e is called the exponent. Exponents can be positive or negative, and floating point numbers in computers represent the tail and exponent separately, plus a sign bit. The binary format for decimals is the same for almost all hardware and languages. This is a standard called IEEE754, which defines two formats: 32-bit for float and 64-bit for double, where the 1 bit represents the symbol. The 23 digits indicate the mantissa and the 8 digits indicate the exponent. In 64-bit format, 1 bit represents a symbol, 52 bits represent a mantissa, and 11 bits represent an exponent. There are also some complicated details in IEEE754 that are difficult to understand and not commonly used, so I won’t cover them in this article for now. Some people also ask, why does the underlying data of the computer have to be represented in binary? Computer is nothing more than an electrical appliance, there are countless resistors and capacitors, when the computer through alternating current, encountered capacitor is low voltage with 0, encountered resistance is high voltage with 1, so the bottom of the computer can only be binary, because he can only represent high and low voltage. This is analog and digital circuits.




Problem solution


Solution 1: When using floating-point numbers, we can change the decimal to int or long, and then restore float or double. For example, we can calculate the sum between 0.1 and 0.9, as shown in the figure below.

[Java]

Plain text view
Copy the code

?
1
2
3
4
5
6
// Take the sum of 1-9 and divide by 10
int
sum =
0
;
for
(
int
i =
1
; i <=
9
; i++) {

sum+=i;
}
System.out.println(sum/
10.0
);
/ / 4.5

Scheme 2: Use the java.math.BigDecimal class to do the math. For example, 0.1+0.7, look at the following code.
[Java]

Plain text view
Copy the code

?
01
02
03
04
05
06
07
08
09
10
package
cam.itheima.demo;
import
java.math.BigDecimal;
public
class
Demo5 {

public
static
void
main(String[] args) {

BigDecimal bd1 =
new
BigDecimal(
"0.1"
);

BigDecimal bd2 =
new
BigDecimal(
"0.7"
);

BigDecimal sum = bd1.add(bd2);

System.out.println(sum);

}
}

Both schemes have advantages and disadvantages. The first scheme is fast and does not consume too much memory. However, if the data is too large, int and long cannot be represented. Scheme 2 can represent large data, but the speed is slow and the memory consumption is high.
Conclusion:
This paper describes the phenomenon of floating point inaccuracy in Java and explains the reason of floating point inaccuracy by describing the principle of floating point representation at the bottom of the computer, and finally puts forward the solution of floating point in accurate operation.