BigDecimal 常用锦囊

知识点

CompareTo

算式 使用 compareTo 值
a == b a.compareTo(b) 0
a > b a.compareTo(b) 1
a < b a.compareTo(b) -1

推理:

例子 推荐 code 不推荐 code
a > b a.compareTo(b) > 0 a.compareTo(b) == 1
a >= b a.compareTo(b) >= 0 a.compareTo(b) > -1
a < b a.compareTo(b) < 0 a.compareTo(b) == -1
a <= b a.compareTo(b) <=0 a.compareTo(b) < 1
a == b a.compareTo(b) == 0 a.compareTo(b) == 0

加减乘除

+-*/ 表达式
add(BigDecimal)
subtract(BigDecimal)
multiply(BigDecimal)
divide(BigDecimal)

equals

a 值 b 值 a.equals(b)值
BigDecimal(1000) BigDecimal(1000) ture
BigDecimal(1000) BigDecimal("1000") true
BigDecimal(100.01) BigDecimal("100.01") false
BigDecimal(100.01) BigDecimal(100.0100) true
BigDecimal("100.01") BigDecimal("100.0100") false

推理:

equals 比较时候相等时候

采用 double 构建和小数位数无关,采用 String 构建与小数位数有关

double 与 String 构建的 BigDecimal,值一样但也是 false

故事

就说说最近吧,最近上班经常用到了一个东西 BigDecimal,然后对我我这不爱动脑的人来说就很要命了,为什么这种说(接下来就尽情嘲笑我吧),我每次用到比较大小都去百度一次,有个哥们那个博客怕被我访问了 100 来次,但是还是记不住,就是因为他用了上面我写了不推荐的那个写法,搞得我头昏眼花,今天咬咬牙,来写写,加深印象。

我每次用到 BigDecimal 的时候,经常要比较大小,这时候呢,我这脑子就不好用了,分不清谁大谁小,当时我脑子大概是这样想的:compareTo 等于 1 是左边大还是又边大,等于-1 了,如果要大于等于怎么办。

搞事情(理论)

compareTo 源码分析

public int compareTo(BigDecimal val) {
    //判断小数位数,区别出是否是字符串构造
    //如果是int或者long则为0,double 则scale是46,但如果是字符串,则有几位算几位
    if (scale == val.scale) {//相等说明是int或者long
        //xs ys 通过移位以及其他运算得出可用于计算的值
        long xs = intCompact; 
        long ys = val.intCompact;
        if (xs != INFLATED && ys != INFLATED) //判断时候超过INFLATED  -2的63次方
            //这就是为什么返回的是 0 1 -1的原因
            return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
    }
    //判断signum函数 具体signum函数是什么鬼自己google
    //具体为正负0:0,正:1,负:-1   NaN:NaN
    int xsign = this.signum();
    int ysign = val.signum();
    if (xsign != ysign)
        return (xsign > ysign) ? 1 : -1;
    if (xsign == 0)
        return 0;
    //忽略符号进行比较  无符号的compareTo
    int cmp = compareMagnitude(val);
    return (xsign > 0) ? cmp : -cmp;
}

equals 源码分析

@Override
public boolean equals(Object x) {
    //常规查看类型
    if (!(x instanceof BigDecimal))
        return false;
    //将Object强转
    BigDecimal xDec = (BigDecimal) x;
    //对比内存地址
    if (x == this)
        return true;
    //对比小数位数,注意:为什么我们采用字符串构建和double构建,虽然小数位数看着一样,但是是false的原因,double的scale有40多位,但是如果是字符串则有几位是几位
    if (scale != xDec.scale)
        return false;
    //移位运算计算可用于计算的紧凑值
    long s = this.intCompact;
    long xs = xDec.intCompact;
    
    if (s != INFLATED) {//-2的63次方
        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());//开始值比较
}

与 Double 比较

采用 Double 很严重一个问题就是精度问题

为什么在很多的项目中会采用 BigDecimal 而不采用 double 呢,或许你有时候也会遇到前端页面显示价格会有 8/9 位小数,这就是因为精度的原因。举个例子当你计算钱或者货物。eg:有个老板有很多的黄金。现在金价 1g 算 350,他本来有 0.03 吨(30kg),这个时候卖了 0.02 吨(20kg),如果是 Double 的话他现在还剩多少?还剩下结果是 0.009999999999998;哦豁,本来只是 2 位小数,现在好家伙几十位。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2990 引用 • 8141 回帖 • 593 关注
1 操作
sirwsl 在 2021-09-06 14:05:32 更新了该帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • PeterChu

    既然写的这么清楚,那我就要白嫖了huaji

    1 回复
  • sirwsl
    捐赠者 作者

    欢迎欢迎 😇