question: What do we see if we compile and run the program below? Public classtest{ Public Static voidMain (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 did not read it correctly! The result is indeed0.0600000000000000050.5800000000000001401.499999999999941.2329999999999999Simple 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. Rounding our first reaction is 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 DoubleRoundDoublevalue) { returnMath.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 in the above4.015*100=401.49999999999994So if we're going to do a precise rounding, we can't do anything with a simple type, Java.text.DecimalFormat does not solve this problem: System.out.println (NewJava.text.DecimalFormat ("0.00"). Format (4.025) ); the output is 4.02BigDecimal in the book "Effective Java" also mentions this principle, float and double can only be used for scientific calculation or engineering calculation, in business computing we need to use Java.math.BigDecimal. There are 4 BigDecimal, we do not care about the two BigInteger to build, then there are two of them: BigDecimal (Doubleval) Translates aDoubleInto a BigDecimal. BigDecimal (string val) translates the string repre sentation of a BigDecimal into a BigDecimal. The above API brief description is quite clear, and 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 of the above is a sufficient method of the detailed description of this paragraph: note:the results of Thisconstructor can somewhat unpredictable. One might assume thatNewBigDecimal (. 1) is exactly equal to. 1, but it's actually equal to. 100000000000000005551115123125782702118158340454101562 5. Because. 1 cannot be represented exactly as aDouble(Or, forThat is matter, as a binary fraction of any finite length). Thus, theLongValue that is being passed in to the constructor are not exactly equal to. 1, appearances nonwithstanding. The (String) constructor, on the other hand, is perfectly predictable:NewBigDecimal (". 1") is exactly equal to. 1, as one would expect. Therefore, it is generally recommended that the (String) constructor being used in preference to ThisOne . If we need accurate calculation, we must 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 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 DoubleAddDoubleV1,Doublev2) Public Static DoubleSubDoubleV1,Doublev2) Public Static DoubleMulDoubleV1,Doublev2) Public Static DoubleDivDoubleV1,Doublev2) Public Static DoubleDivDoubleV1,DoubleV2,intScale ) Public Static DoubleRoundDoubleVintScale ) Appendix source file Arith.java:ImportJava.math.BigDecimal;/*** Because Java's simple type does not accurately operate on floating-point numbers, this tool class provides fine-grained floating-point arithmetic, including subtraction and rounding. */ Public classarith{//Default division operation Precision Private Static Final intDef_div_scale = 10; //This class cannot be instantiated PrivateArith () {}/*** provides accurate addition operations. * @paramv1 summand *@paramV2 Addend *@returntwo parameters of A and*/ Public Static DoubleAddDoubleV1,Doublev2) {BigDecimal B1=NewBigDecimal (double.tostring (v1)); BigDecimal B2=NewBigDecimal (Double.tostring (v2)); returnB1.add (B2). Doublevalue (); } /*** provides accurate subtraction operations. * @paramv1 minuend *@paramv2 *@returnthe difference of two parameters*/ Public Static DoubleSubDoubleV1,Doublev2) {BigDecimal B1=NewBigDecimal (double.tostring (v1)); BigDecimal B2=NewBigDecimal (Double.tostring (v2)); returnb1.subtract (B2). Doublevalue (); } /*** provides accurate multiplication operations. * @paramv1 by multiplier *@paramV2 Multiplier *@returnproduct of two parameters*/ Public Static DoubleMulDoubleV1,Doublev2) {BigDecimal B1=NewBigDecimal (double.tostring (v1)); BigDecimal B2=NewBigDecimal (Double.tostring (v2)); returnb1.multiply (B2). Doublevalue (); } /*** Provide (relative) accurate division operations, when there are no more than an endless situation, accurate to * after the decimal 10 digits, after the number rounded. * @paramV1 Dividend *@paramv2 Divisor *@returntwo parameters of the quotient*/ Public Static DoubleDivDoubleV1,Doublev2) { returnDiv (V1,v2,def_div_scale); } /*** Provide (relative) accurate division operations. When the exception occurs, the scale parameter refers to the fixed precision, and the subsequent numbers are rounded. * @paramV1 Dividend *@paramv2 Divisor *@paramthe scale representation needs to be accurate to several points after the decimal point. * @returntwo parameters of the quotient*/ Public Static DoubleDivDoubleV1,DoubleV2,intScale ) { if(scale<0){ Throw NewIllegalArgumentException ("The scale must is a positive integer or zero"); } BigDecimal B1=NewBigDecimal (double.tostring (v1)); BigDecimal B2=NewBigDecimal (Double.tostring (v2)); returnb1.divide (b2,scale,bigdecimal.round_half_up). Doublevalue (); } /*** Provides precise rounding of decimal digits. * @paramv need to round the number *@paramA few * after the decimal point@returnresults after rounding*/ Public Static DoubleRoundDoubleVintScale ) { if(scale<0){ Throw NewIllegalArgumentException ("The scale must is a positive integer or zero"); } BigDecimal b=NewBigDecimal (double.tostring (v)); BigDecimal One=NewBigDecimal ("1"); returnb.divide (one,scale,bigdecimal.round_half_up). Doublevalue (); }};
On the arithmetic precision of double type in Java