1. Introduction
To borrow the words from the book "Effactive Java", the main design goals of float and double types are for scientific computing and engineering computing. They perform binary floating point operations, which are carefully designed to provide more accurate fast approximation over the wide-area numerical range. However, they do not provide completely accurate results and should not be used in situations where accurate results are required. However, commercial calculations often require accurate results, and BigDecimal comes in handy at this time.
2. Introduction to BigDecimal
BigDecimal consists of an integer non-scale value of any precision and a 32-bit integer scale. If it is zero or positive, the scale is the number of digits after the decimal point. If it is a negative number, multiply the non-scaling value of the number by a negative scale power of 10. Therefore, the value represented by BigDecimal is (unscaledValue × 10-scale).
3. Test code
3.1 Constructor (the main test parameter types are two common constructors with double and String)
The code copy is as follows: BigDecimal aDouble =new BigDecimal(1.22);
System.out.println("construct with a double value: " + aDouble);
BigDecimal aString = new BigDecimal("1.22");
System.out.println("construct with a String value: " + aString);
What do you think the output will be? If you don't think the first one will output 1.22, then congratulations on the answer correctly, the output result is as follows:
Copy the code as follows: construct with a doublevalue:1.2199999999999999999733546474089962430298328399658203125
construct with a String value: 1.22
Description of JDK:
1. The results of the construction method with parameter type double are unpredictable. Some people might think that the BigDecimal created by writing newBigDecimal(0.1) in Java is exactly equal to 0.1 (non-scaling value 1, whose scale is 1), but it is actually equal to 0.10000000000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be expressed accurately as a double (or for this case it cannot be expressed as any finite length binary decimal). In this way, the value passed into the construction method will not be exactly equal to 0.1 (although it is surface equal to that value).
2. On the other hand, the String construction method is completely predictable: writing to newBigDecimal("0.1") will create a BigDecimal, which is exactly equal to the expected 0.1. Therefore, in comparison, it is generally recommended to use the String constructor first.
3. When the double must be used as the source of BigDecimal, please note that this constructor provides an accurate conversion; it does not provide the same result as the following operations: first use the Double.toString(double) method, and then use the BigDecimal(String) constructor to convert the double to String. To get the result, use the static valueOf(double) method.
3.2 Addition operation
The code copy is as follows: BigDecimal a =new BigDecimal("1.22");
System.out.println("construct with a String value: " + a);
BigDecimal b =new BigDecimal("2.22");
a.add(b);
System.out.println("aplus b is : " + a);
It's easy to think that it will output:
Copy the code as follows: construct with a Stringvalue: 1.22
a plus b is :3.44
But in fact a plus b is : 1.22
4. Source code analysis
4.1 valueOf(doubleval) method
Copy the code as follows: public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannotfastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
returnnew BigDecimal(Double.toString(val));//See the third point in 3.1 about the JDK description
}
4.2 add(BigDecimal augend) method
public BigDecimal add(BigDecimal augend) { long xs = this.intCompact; //BigDecimal represented by an integer number, for example a has an intCompact value of 122 long ys = augend.intCompact;//Same as above BigInteger fst = (this.intCompact !=INFLATED) ?null : this.intVal;//Initialize the value of BigInteger, intVal is a property of BigInteger type BigInteger snd =(augend.intCompact !=INFLATED) ?null : augend.intVal; int rscale =this.scale;//The decimal places long sdiff = (long)rscale - augend.scale;//The difference between decimal places if (sdiff != 0) {//The decimal places with the most decimal places are the result if (sdiff < 0) { int raise =checkScale(-sdiff); rscale =augend.scale; if (xs ==INFLATED || (xs = longMultiplyPowerTen(xs,raise)) ==INFLATED) fst =bigMultiplyPowerTen(raise); }else { int raise =augend.checkScale(sdiff); if (ys ==INFLATED ||(ys =longMultiplyPowerTen(ys,raise)) ==INFLATED) snd = augend.bigMultiplyPowerTen(raise); } } if (xs !=INFLATED && ys !=INFLATED) { long sum = xs + ys; if ( (((sum ^ xs) &(sum ^ ys))) >= 0L)//Judge whether there is any overflow. Return BigDecimal.valueOf(sum,rcale);//Return BigDecimal instance obtained using BigDecimal's static factory method} if (fst ==null) fst =BigInteger.valueOf(xs);//BigInteger's static factory method if (snd ==null) snd =BigInteger.valueOf(ys); BigInteger sum =fst.add(snd); return (fst.signum == snd.signum) ?new BigDecimal(sum,INFLATED, rcale, 0) : new BigDecimal(sum,compactValFor(sum),rcale, 0);//Return the BigDecimal object obtained by other construction methods}The above is just an analysis of the addition source code. Subtraction, multiplication and division actually return a new BigDecimal object. Because BigInteger and BigDecimal are both immutable, a new object will be generated when performing each step of operation, so a.add(b); Although the addition operation is performed, a does not save the value after the addition operation. The correct usage should be a=a.add(b);
5. Summary
(1) Commercial calculations use BigDecimal.
(2) Try to use constructors with parameter type String.
(3) BigDecimals are immutable. When performing each step of operation, a new object will be generated. Therefore, when performing addition, subtraction, multiplication and division, you must save the value after the operation.
(4) We often tend to ignore some implementation details of the underlying JDK, resulting in errors, so we need to pay more attention.
Reference: Class BigDecimal