Remember writing test cases a long time ago and inadvertently discovering
Double c=2.31;
Double d=0.1;
System.out.println (C/D);
The final output is unexpectedly 23.099999999999998, rather than the simple 23.1, it is obvious that such results will be problematic in many cases, and the use of window calculator software, but can get the correct results, is very puzzled. Today we see a precise calculation method, which is hereby recorded.
Reprinted from: http://blog.csdn.net/hjxhjh/article/details/6025442
There is a problem with the numerical calculation today. The program is as follows:
Double A = (3.3-2.4)/0.1;
System.out.println (a);
You may think the result is simple, not just 9, in fact, the result is: 8.999999998, why? I looked through some information and finally found out why.
Why are floating-point numbers losing precision?
Binary representation of decimal numbers may not be accurate
It is not uncommon for floating-point numbers or double-precision floating-point numbers to be accurately represented. The reason why floating-point numbers are not represented in decimal notation is attributed to the way the CPU represents floating-point numbers. In this case, you may sacrifice some precision, and some floating-point arithmetic will introduce errors. As an example of the above-mentioned case, the binary representation of 2.4 is not exactly 2.4. Instead the nearest binary representation is 2.3999999999999999. The reason is that the floating-point number consists of two parts: exponent and mantissa. The value of a floating-point number is actually calculated from a specific mathematical formula. The loss of precision you encounter will be encountered in any operating system and programming environment.
Note: You can use the binary Coded Decimal (BCD) library to maintain precision. The BCD digital encoding method encodes each decimal digit bit separately.
Type mismatch
You may have mixed floating-point and double-precision floating-point number types. Make sure that all data types are the same when you are doing mathematical operations.
Note: A variable of type float has a precision of only 7 bits, whereas a variable of type double has a precision of 15 bits.
How do I calculate floating-point accuracy?
Simple floating-point type float and double in Java are not capable of operation. It's not just Java, it's also a problem in many other programming languages. In most cases, the result of the calculation is accurate, but try a few more times (you can do a loop) to try out a similar error. Now we finally understand why we have BCD code.
This problem is quite serious, if you have $9.999999999999, your computer is not going to think you can buy 10 dollars of merchandise.
Special currency types are available in some programming languages to handle this situation, but Java does not. Now let's look at how to solve this problem.
Rounded
Our first reaction was to do rounding. The round method in the math class cannot be set to retain several decimals, and we can only do this (keep two bits):
Public double round (double value) {
Return Math.Round (value*100)/100.0;
}
Unfortunately, the above code does not work properly, passing 4.015 to this method it will return 4.01 instead of 4.02, as we saw above
4.015*100=401.49999999999994
So if we're going to do exact rounding, we can't do anything with a simple type.
Java.text.DecimalFormat also does not solve this problem:
System.out.println (New Java.text.DecimalFormat ("0.00"). Format (4.025));
Output is 4.02
BigDecimal
This principle is also mentioned in the book "Effective Java", where float and double can only be used for scientific calculations or engineering calculations, and we use java.math.BigDecimal in business calculations. There are 4 bigdecimal, we do not care about the two that are made with BigInteger, and then there are two of them:
BigDecimal (double val)
Translates a double into a BigDecimal.
BigDecimal (String val)
Translates the String repre sentation of a BigDecimal into a BigDecimal.
The above API brief description is fairly clear, and usually, the one above is easier to use. We may not want to use it, what is the problem? When there is a problem, only to find out which one of the above-mentioned detailed description of the method has such a paragraph:
Note:the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal (. 1) is exactly equal to. 1, but it's actually equal to. 1000000000000000055511151231 257827021181583404541015625. Because. 1 cannot be represented exactly as a double (or, for that matter, as a bi nary fraction of any finite length). Thus, the Long value that's being passed in to the constructor are not exactly equal to. 1, appearances nonwithstanding.
The (String) constructor, on the other hand, is perfectly predictable:new BigDecimal (". 1") are exactly equal to. 1, as one would expect. Therefore, it is generally recommended and that the (String) constructor being used in preference to this one.
If we need accurate calculation, it is necessary to use string to build BigDecimal! In "effective Java" the example is to use string to build BigDecimal, but the book does not emphasize this point, this may be a small mistake it.
Solution Solutions
Now we can solve this problem, the principle is to use BigDecimal and must use string to build enough.
But imagine, if we're going to do an addition, we need to convert two floating-point numbers to string, then BigDecimal, call the Add method on one of them, pass in another as a parameter, and then transform the result of the operation (BigDecimal) into a floating-point number. Can you endure such a tedious process? Below we provide a tool class arith to simplify the operation. It provides the following static methods, including subtraction and rounding:
public static double Add (Double v1,double v2)
public static double sub (double v1,double v2)
public static double Mul (Double v1,double v2)
public static double div (Double v1,double v2)
public static double div (double v1,double v2,int scale)
public static double round (double v,int scale)
Appendix
Source file Arith.java:
Import Java.math.BigDecimal;
public class arith{
Default division Operation Precision
private static final int def_div_scale = 10;
This class cannot be instantiated
Private Arith () {
}
public static double Add (Double v1,double v2) {
BigDecimal B1 = new BigDecimal (double.tostring (v1));
BigDecimal b2 = new BigDecimal (double.tostring (v2));
Return B1.add (B2). Doublevalue ();
}
public static double sub (double v1,double v2) {
BigDecimal B1 = new BigDecimal (double.tostring (v1));
BigDecimal b2 = new BigDecimal (double.tostring (v2));
Return B1.subtract (B2). Doublevalue ();
}
public static double Mul (Double v1,double v2) {
BigDecimal B1 = new BigDecimal (double.tostring (v1));
BigDecimal b2 = new BigDecimal (double.tostring (v2));
Return b1.multiply (B2). Doublevalue ();
}
public static double div (Double v1,double v2) {
Return Div (V1,v2,def_div_scale);
}
public static double div (double v1,double v2,int scale) {
if (scale<0) {
throw New IllegalArgumentException (
"The scale must is a positive integer or zero");
}
BigDecimal B1 = new BigDecimal (double.tostring (v1));
BigDecimal b2 = new BigDecimal (double.tostring (v2));
Return B1.divide (B2,SCALE,BIGDECIMAL.ROUND_HALF_UP). Doublevalue ();
}
public static double round (double V,int scale) {
if (scale<0) {
throw New IllegalArgumentException (
"The scale must is a positive integer or zero");
}
BigDecimal B = New BigDecimal (double.tostring (v));
BigDecimal one = new BigDecimal ("1");
Return B.divide (ONE,SCALE,BIGDECIMAL.ROUND_HALF_UP). Doublevalue ();
}
};
for Double d = 2.4;
System.out.println (d);//output 2.4, but not 2.3999999999999999?
Read some of the data, when a single output double value, can be correctly displayed in decimal, specifically why, I also indefinitely, but for floating point calculation, floating point calculation refers to the operation of floating point number, which is usually accompanied by the approximation or rounding due to the inability to accurately represent. may be related to Floatingdecimal (d). Tojavaformatstring () of the Double.tostring method
Guess it's about 2.3999999999999999 out of the accuracy of the output, so it's been intercepted.
Floating-point calculations in Java