public class Test{ public static void main(String args[]){ System.out.println(0.05+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(123.3/100); }};
You are not mistaken! The result is indeed
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
The float and double types of simple floating point numbers in Java cannot be computed. Not only Java, but also in many other programming languages. In most cases, the calculation results are accurate, but you can try multiple times (you can do a loop) to try out errors similar to the above. Now we finally understand why we need BCD code.
This problem is quite serious. If you have 9.999999999999 yuan, your computer will not think you can buy 10 yuan of goods.
Some Programming Languages provide special currency types to handle this situation, but Java does not. Now let's take a look at how to solve this problem.
Rounding
Our first response was rounding. The round method in the math class cannot be set to retain a few decimal places. We can only keep two places like this ):
public double round(double value){ return Math.round(value*100)/100.0;}
Unfortunately, the code above does not work normally. If you pass 4.015 to this method, it will return 4.01 instead of 4.02, as we can see above
4.015*100 = 401.49999999999994
Therefore, if we want to perform precise rounding, we cannot use simple types for any operation.
Java. Text. decimalformat cannot solve this problem either:
System.out.println(new java.text.DecimalFormat("0.00").format(4.025));
The output is 4.02
Bigdecimal
This principle is also mentioned in objective java. Float and double can only be used for scientific computing or engineering computing. In commercial computing, java. Math. bigdecimal is used. Bigdecimal has a total of four creation methods. We don't care about the two that can be created using biginteger. There are two other methods:
Bigdecimal (double Val)
Translates a double into a bigdecimal.
Bigdecimal (string Val)
Translates the string repre sentation of a bigdecimal into a bigdecimal.
The Brief description of the above API is quite clear, and it is usually easier to use the above one. We may use it if we don't want it. What's the problem? When a problem occurs, the detailed description of the above method is as follows:
Note: The results of this constructor can be somewhat unpredictable. one might assume that new bigdecimal (. 1) is exactly equal. 1, but it is actually equal. 1000000000000000055511151231257827021181583404541015625. this is so because. 1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length ). thus, the long value that is being passed in to the constructor is not exactly equal. 1, appearances nonwithstanding.
The (string) constructor, on the other hand, is perfectly predictable: New bigdecimal (". 1 ") is exactly equal. 1, as one wocould CT. therefore, it is generally recommended that the (string) constructor be used in preference to this one.
It turns out that if we need precise calculation, we have to use string to create bigdecimal! The example in objective Java uses string to create bigdecimal, but this is not emphasized in the book. This may be a small mistake.
Solution
Now we can solve this problem. The principle is to use bigdecimal and must use string to create it.
But imagine, if we want to do an addition operation, we need to first convert two floating point numbers into strings, and then convert them into bigdecimal. Call the add method on one of them and input another as the parameter, then convert the result of the operation (bigdecimal) to a floating point number. Can you endure this cumbersome process? The following provides a tool class Arith to simplify operations. It provides the following static methods, including addition, subtraction, multiplication, division, 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)
Import java. Math. bigdecimal;/*** Because Java's simple type cannot perform exact operations on floating point numbers, this tool class provides precise * real floating point operations, including addition, subtraction, multiplication, division, and rounding. */Public class Arith {// default Division calculation precision: Private Static final int def_div_scale = 10; // This class cannot be instantiated private Arith () {}/*** provides precise addition operations. * @ Param V1 add count * @ Param V2 add count * @ return and */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 ();}/*** provides precise subtraction. * @ Param V1 subtrahend * @ Param V2 subtrahend * @ Return Difference Between Two Parameters */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 ();}/*** provides exact multiplication. * @ Param V1 multiplier * @ Param V2 multiplier * @ return product of two parameters */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 ();}/*** provides (relatively) Precise Division operations. In case of Division, the Division is accurate to * 10 digits after the decimal point, and the subsequent digits are rounded down. * @ Param V1 divisor * @ Param V2 divisor * @ return two parameter vendors */public static double Div (double V1, double V2) {return Div (V1, V2, def_div_scale);}/*** provides (relatively) accurate Division operations. In case of division, the scale parameter determines * the precision, and the number is rounded down. * @ Param V1 divisor * @ Param V2 divisor * @ Param scale indicates the number of digits after the decimal point. * @ Return operator of two parameters */public static double Div (double V1, double V2, int scale) {If (scale <0) {Throw new illegalargumentexception ("the scale must be 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 ();}/*** provides precise rounded decimal places. * @ Param v the number to be rounded off * @ Param scale the number of digits to be retained after the decimal point * @ return the result after rounding */public static double round (Double V, int scale) {If (scale <0) {Throw new illegalargumentexception ("the scale must be 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 () ;}}; finally, we use the exact calculation provided by bigdecimal to test the public class test {public static void main (string [] ARGs) {// use a floating point number directly for calculation. The result is a problematic system. out. println (0.01 + 0.05); // After the bigdecimal class is used for computation, the system can be accurately calculated. out. println (Arith. add (0.05, 0.01 ));}}
Console output:
0.060000000000000005
0.06
Rounding mode for bigdecimal Precision Calculation
Round_ceiling. Static variables in the Java. Math. bigdecimal class
If bigdecimal is positive, round_up is performed. If bigdecimal is negative, round_down is performed.
Round_down. Static variables in the Java. Math. bigdecimal class
Never add a number before dropping (that is, truncating) decimal places.
Round_floor. Static variables in the Java. Math. bigdecimal class
If bigdecimal is positive, round_up is performed. If bigdecimal is negative, round_down is performed.
Round_half_down. Static variables in the Java. Math. bigdecimal class
If part>. 5 is discarded, round_down is performed. Otherwise, round_down is performed.
Static variables in the round_half_even. Class java. Math. bigdecimal
If the number on the left of the discard part is an odd number, perform the round_half_up operation. If the number is an even number, perform the round_half_down operation.
Round_half_up. Static variables in the Java. Math. bigdecimal class
If you discard part> =. 5, round_up is performed. Otherwise, round_down is performed.
Round_unnecessary. Static variables in the Java. Math. bigdecimal class
This "pseudo-rounding mode" actually requires an exact result for the operation, so no rounding is required.
Round_up. Static variables in the Java. Math. bigdecimal class
Always add a number before a non-zero decimal point (that is, truncation.