您的位置:首页 > 快讯 > 聚焦 >

环球观天下!上海牛巨仁网络>>>用了BigDecimal后,计算结果就一定精确了?

来源: 这个IT有点暖 时间: 2022-08-09 09:30:24

上海牛巨仁编者按:BigDecimal,相信对于很多人来说都不陌生,很多人都知道他的用法,这是一种java.math包中提供的一种可以用来进行精确运算的类型。

很多人都知道,在进行金额表示、金额计算等场景,不能使用double、float等类型,而是要使用对精度支持的更好的BigDecimal。

所以,很多支付、电商、金融等业务中,BigDecimal的使用非常频繁。但是,如果误以为只要使用BigDecimal表示数字,结果就一定精确,那就大错特错了!


(资料图片)

在之前的一篇文章中,我们介绍过,使用BigDecimal的equals方法并不能验证两个数是否真的相等( 为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?)。

除了这个情况,BigDecimal的使用的第一步就是创建一个BigDecimal对象,如果这一步都有问题,那么后面怎么算都是错的!

那到底应该如何正确的创建一个BigDecimal?

关于这个问题,我Review过很多代码,也面试过很多一线开发,很多人都掉进坑里过。这是一个很容易被忽略,但是又影响重大的问题。

关于这个问题,在《阿里巴巴Java开发手册》中有一条建议,或者说是要求:

这是一条【强制】建议,那么,这背后的原理是什么呢?

想要搞清楚这个问题,主要需要弄清楚以下几个问题:

1、为什么说double不精确? 2、BigDecimal是如何保证精确的?

在知道这两个问题的答案之后,我们也就大概知道为什么不能使用BigDecimal(double)来创建一个BigDecimal了。

double为什么不精确

首先,计算机是只认识二进制的,即0和1,这个大家一定都知道。

那么,所有数字,包括整数和小数,想要在计算机中存储和展示,都需要转成二进制。

十进制整数转成二进制很简单,通常采用"除2取余,逆序排列"即可,如10的二进制为1010。

但是,小数的二进制如何表示呢?

十进制小数转成二进制,一般采用"乘2取整,顺序排列"方法,如0.625转成二进制的表示为0.101。

但是,并不是所有小数都能转成二进制,如0.1就不能直接用二进制表示,他的二进制是0.000110011001100… 这是一个无限循环小数。

所以,计算机是没办法用二进制精确的表示0.1的。也就是说,在计算机中,很多小数没办法精确的使用二进制表示出来。

那么,这个问题总要解决吧。那么,人们想出了一种采用一定的精度,使用近似值表示一个小数的办法。这就是IEEE 754(IEEE二进制浮点数算术标准)规范的主要思想。

IEEE 754规定了多种表示浮点数值的方式,其中最常用的就是32位单精度浮点数和64位双精度浮点数。

在Java中,使用float和double分别用来表示单精度浮点数和双精度浮点数。

所谓精度不同,可以简单的理解为保留有效位数不同。采用保留有效位数的方式近似的表示小数。

所以,大家也就知道为什么double表示的小数不精确了。

接下来,再回到BigDecimal的介绍,我们接下来看看是如何表示一个数的,他如何保证精确呢?

BigDecimal如何精确计数?

如果大家看过BigDecimal的源码,其实可以发现,实际上一个BigDecimal是通过一个"无标度值"和一个"标度"来表示一个数的。

在BigDecimal中,标度是通过scale字段来表示的。

而无标度值的表示比较复杂。当unscaled value超过阈值(默认为Long.MAX_VALUE)时采用intVal字段存储unscaled value,intCompact字段存储Long.MIN_VALUE,否则对unscaled value进行压缩存储到long型的intCompact字段用于后续计算,intVal为空。

BigDecimal中提供了一个通过double创建BigDecimal的方法——BigDecimal(double) ,但是,同时也给我们留了一个坑!

因为我们知道,double表示的小数是不精确的,如0.1这个数字,double只能表示他的近似值。

所以,当我们使用new BigDecimal(0.1)创建一个BigDecimal 的时候,其实创建出来的值并不是正好等于0.1的。

而是0.1000000000000000055511151231257827021181583404541015625。这是因为doule自身表示的只是一个近似值。

以上想法,与诸君共勉!如果说没有记住的,就保存下来多看几遍。更多内容百度:上海牛巨仁。

每日感悟❤❤❤

很久以前,有一个国王想找到一句话,它能让高兴的人听了难过,难过的人听了高兴。这句史上最神奇的话就是——这一切都会过去的。不管是好的还是坏的,没有一件东西可以永恒不变。当你失败痛苦的时候,你要告诉自己:这一切都会过去的。当你成功得意忘形的时候,你也要知道:这一切都会过去的。

责任编辑:

标签: double