BigDecimal介绍

Double存在几个问题:

  • 计算时容易出现不精确的问题
    1
    2
    3
    4
    System.out.println(12.3 + 45.6);
    // 57.900000000000006
    System.out.println(1.14 / 100);
    // 0.011399999999999999
  • 判断是否相等时,如果位数超过了16位,会出现问题:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 16位,不相等
    double a = 1.1234567890123451;
    double b = 1.1234567890123452;
    System.out.println(a == b); // false

    // 17位,相等
    double a = 1.12345678901234561;
    double b = 1.12345678901234567;
    System.out.println(a == b); // true

因此,在电商与金融等对数据的敏感程度较高(精度要求较高)的场景下一般使用BigDecimal。

BigDecimal基本操作

加法add

1
2
// num1 + num2
num1.add(num2)

减法substract

1
2
// num1 - num2
num1.substract(num2)

乘法multiply

1
2
// num1 * num2
num1.multiply(num2)

除法divide

1
BigDecimal.divide(BigDecimal divisor,int scale, int roundingMode)

第一个参数是除数,第二个参数代表保留几位小数,第三个代表的是使用的模式。

  • BigDecimal.ROUND_DOWN:直接省略多余的小数,比如1.28如果保留1位小数,得到的就是1.2
  • BigDecimal.ROUND_UP:直接进位,比如1.21如果保留1位小数,得到的就是1.3
  • BigDecimal.ROUND_HALF_UP:四舍五入,2.35保留1位,变成2.4
  • BigDecimal.ROUND_HALF_DOWN:四舍五入,2.35保留1位,变成2.3

BigDecimal比较大小

下面是equalscompareTo两个比较大小方法的一个示例:

1
2
3
4
5
6
7
8
public class BigDecimalDemo {
    public static void main(String [] args) {
        BigDecimal decimal1 = new BigDecimal("222");
        BigDecimal decimal2 = new BigDecimal("222.000000");
        System.out.println(decimal1.equals(decimal2));
        System.out.println(decimal1.compareTo(decimal2));
    }
}

运行结果不出所料,BigDecimal的equals方法当精度不一样的时候也当做不相等,而compareTo方法却可以忽略精度的不同,只比较数值是否相同

源码分析

BigDecimal的equals方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* Compares this {@code BigDecimal} with the specified
* {@code Object} for equality. Unlike {@link
* #compareTo(BigDecimal) compareTo}, this method considers two
* {@code BigDecimal} objects equal only if they are equal in
* value and scale (thus 2.0 is not equal to 2.00 when compared by
* this method).
*
* @param x {@code Object} to which this {@code BigDecimal} is
* to be compared.
* @return {@code true} if and only if the specified {@code Object} is a
* {@code BigDecimal} whose value and scale are equal to this
* {@code BigDecimal}'s.
* @see #compareTo(java.math.BigDecimal)
* @see #hashCode
*/
@Override
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);

return this.inflated().equals(xDec.inflated());
}

源码里说的很详细,equals方法比较value和scale(数值和精度),精度不一样,也返回false

BigDecimal的compareTo方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* Compares this {@code BigDecimal} with the specified
* {@code BigDecimal}. Two {@code BigDecimal} objects that are
* equal in value but have a different scale (like 2.0 and 2.00)
* are considered equal by this method. This method is provided
* in preference to individual methods for each of the six boolean
* comparison operators ({@literal <}, ==,
* {@literal >}, {@literal >=}, !=, {@literal <=}). The
* suggested idiom for performing these comparisons is:
* {@code (x.compareTo(y)} &lt;<i>op</i>&gt; {@code 0)}, where
* &lt;<i>op</i>&gt; is one of the six comparison operators.
*
* @param val {@code BigDecimal} to which this {@code BigDecimal} is
* to be compared.
* @return -1, 0, or 1 as this {@code BigDecimal} is numerically
* less than, equal to, or greater than {@code val}.
*/
public int compareTo(BigDecimal val) {
// Quick path for equal scale and non-inflated case.
if (scale == val.scale) {
long xs = intCompact;
long ys = val.intCompact;
if (xs != INFLATED && ys != INFLATED)
return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
}
int xsign = this.signum();
int ysign = val.signum();
if (xsign != ysign)
return (xsign > ysign) ? 1 : -1;
if (xsign == 0)
return 0;
int cmp = compareMagnitude(val);
return (xsign > 0) ? cmp : -cmp;
}

compareTo也说得很详细,数值相同但是精度不同的两个数(例如2.0和2.00)被认为是相等的两个数,返回0。另外对于a.compareTo(b)方法

  • a<b,返回-1
  • a=b,返回0
  • a>b,返回1

参考


----------- 本文结束啦感谢您阅读 -----------

赞赏一杯咖啡

欢迎关注我的其它发布渠道