Implement precise floating point calculation in Java

Source: Internet
Author: User

Question:

What do we see if we compile and run the following program?

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)



Appendix



Source File Arith. java:



Import java. math. BigDecimal;



/**

* Because Java's simple types cannot accurately perform floating-point operations, this tool provides

* A real floating point number operation, including addition, subtraction, multiplication, division, and rounding.

*/

Public class Arith {



// Default division operation 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 addend

* @ Return the sum of the two parameters

*/

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 operations.

* @ 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 precise multiplication.

* @ Param v1 Multiplier

* @ Param v2 Multiplier

* @ Return the 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) accurate Division operations, accurate

* 10 digits after the decimal point, and the digits after the decimal point are rounded down.

* @ Param v1 Divisor

* @ Param v2 Divisor

* @ Return 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 indicates

* Set the precision. The number is rounded down.

* @ Param v1 Divisor

* @ Param v2 Divisor

* @ Param scale indicates the number of digits after the decimal point.

* @ Return parameter vendors

*/

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 rounding of decimal places.

* @ Param v refers to the number rounded up.

* @ Param scale: number of digits after the decimal point

*

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.