About the operation precision of Double type in java

About the operation precision of Double type in java

Title Accurate Calculation of Floating Point Numbers in Java AYellow (Original) Modified    
Keyword Java Floating Point Numbers Precise Calculation   
Problem:
If we compile and run the following program, what will we see?
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 read that right! The result is indeed
0.060000000000000005
0.580000000000001
401.49999999999994
1.2329999999999999
The simple floating point types float and double in Java cannot operate. Not only Java, but also many other programming languages. In most cases, the result of the calculation is accurate, but after a few tries (you can do a loop) you can try something like the above error. Now I finally understand why there is a BCD code.
The 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 specialized currency types to handle this situation, but Java does not. Now let's see how to solve this problem.
 
Rounding
Our first reaction was to do rounding. The round method in the Math class cannot set the number of decimal places, we can only do like this (two digits):
public double round(double value){
    return Math.round(value*100)/100.0;
}
Unfortunately, the above The code doesn't work properly, passing 4.015 to this method will return 4.01 instead of 4.02, as we saw above
4.015*100=401.49999999999994
So if we want to do exact rounding, we can't do anything with simple types
java .text.DecimalFormat doesn't solve this either:
System.out.println(new java.text.DecimalFormat("0.00").format(4.025)); The
output is 4.02
 
BigDecimal
is also mentioned in the book "Effective Java" According to this principle, float and double can only be used for scientific calculation or engineering calculation. In commercial calculation, we use java.math.BigDecimal. BigDecimal has a total of 4 methods, and we don't care about the two using BigInteger, so there are two more, they are:
BigDecimal(double val) 
          Translates a double into a BigDecimal. 
BigDecimal(String val) 
          Translates the String repre sentation of a BigDecimal into a BigDecimal.
The API brief above is fairly explicit, and in general, the above one is easier to use. We may use it without even thinking about it, what is the problem? When something went wrong, I found out that there is a paragraph in the detailed description of which of the above methods is sufficient:
Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1 , but it is actually equal to .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 to .1, appearances nonwithstanding. 
The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.
It turns out that if we need accurate calculation, we must use String to create BigDecimal! The example in the "Effective Java" book is to use String to create BigDecimal, but the book does not emphasize this point, which may be a small mistake.
 
Solution
Now we can solve this problem, the principle is to use BigDecimal and make sure to use String.
But imagine, if we want to do an addition operation, we need to convert two floating point numbers to String first, and then make a BigDecimal, call the add method on one of them, pass the other one as a parameter, and then put the result of the operation ( BigDecimal) and then convert it to a floating point number. Can you put up with such a cumbersome process? Below we provide a tool class Arith to simplify the operation. It provides the following static methods, including addition, subtraction, multiplication and 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;
/**
 * Since Java's simple types cannot perform precise operations on floating-point numbers, this utility class provides precise
 floating-point operations, including addition, subtraction, multiplication, and division, and rounding.
 */
public class Arith{
    //Default division precision
    private static final int DEF_DIV_SCALE = 10;
    //This class cannot instantiate
    private Arith(){
    }
 
    /**
     * Provides accurate addition.
     *  @param  v1 addend
     *  @param  v2 addend
     *  @return  sum of 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 exact subtraction.
     *  @param  v1 minuend
     *  @param  v2 minuend
     * @return the difference of 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 multiplicand
     * @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 a (relatively) exact division operation, which is accurate to
     * 10 decimal places after the decimal point, the following figures are rounded up.
     * @param v1 dividend
     * @param v2 divisor
     * @return quotient of two parameters
     */
    public static double div(double v1,double v2){
        return div(v1,v2,DEF_DIV_SCALE);
    }
 
    /**
     * provide (relative ) exact division operation. When there is an inexhaustible division, the scale parameter refers to
     * Fixed precision, subsequent numbers are rounded off.
     * @param v1 dividend
     * @param v2 divisor
     * @param scale indicates that it needs to be accurate to a few decimal places.
     * @return the quotient 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 accurate decimal rounding.
     * @param v the number to be rounded
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    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();
    }
}; 

 

In this way, the data calculation problem of calculating the double type can be handled. 
In addition, add the method of JavaScript rounding: 
decimal point problem 
Math.round(totalAmount*100)/100 (reserve 2 digits) 

function formatFloat(src, pos) 

  return Math.round(src*Math.pow(10, pos))/ Math.pow(10, pos); 

 

 

double f = 4.025;
BigDecimal b = new BigDecimal(f);
double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println(f1);

String strF3 = String.format("%.2f", 4.025);
System.out.println(strF3);

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325057739&siteId=291194637