当前位置:网站首页>BigDecimal除法的精度问题
BigDecimal除法的精度问题
2022-07-05 16:49:00 【全栈程序员站长】
大家好,又见面了,我是你们的朋友全栈君。
BigDecimal除法的精度问题
在使用BigDecimal的除法时,遇到一个鬼畜的问题,本以为的精度计算,结果使用返回0,当然最终发现还是自己的使用姿势不对导致的,因此记录一下,避免后面重蹈覆辙
I. 问题抛出
在使用BigDecimal做高精度的除法时,一不注意遇到了一个小问题,如下
@Test
public void testBigDecimal() {
BigDecimal origin = new BigDecimal(541253);
BigDecimal now = new BigDecimal(12389431);
BigDecimal val = origin.divide(now, RoundingMode.HALF_UP);
System.out.println(val);
origin = new BigDecimal(541253);
now = new BigDecimal(12389431.3);
val = origin.divide(now, RoundingMode.HALF_UP);
System.out.println(val);
origin = new BigDecimal(541253.4);
now = new BigDecimal(12389431);
val = origin.divide(now, RoundingMode.HALF_UP);
System.out.println(val);
}
复制代码上面的输出是什么 ?
0
0
0.043686703610520937021487456961257
复制代码为什么前面两个会是0呢,如果直接是 541253 / 12389431 = 0 倒是可以理解, 但是BigDecimal不是高精度的计算么,讲道理不应该不会出现这种整除的问题吧
我们知道在BigDecimal做触发时,可以指定保留小数的参数,如果加上这个,是否会不一样呢?
BigDecimal origin = new BigDecimal(541253);
BigDecimal now = new BigDecimal(12389431);
BigDecimal val = origin.divide(now, 5, RoundingMode.HALF_UP);
System.out.println(val);
复制代码输出结果为:
0.04369
复制代码所以说在指定了保留小数之后,则没有问题,所以大胆的猜测一下,是不是上面的几种case中,由于scale值没有指定时,默认值不一样,从而导致最终结果的精度不同呢?
简单的深入源码分析一下,执行的方式为 origin.divide(now, RoundingMode.HALF_UP);, 所以这个scale参数就瞄准origin对象,而这个对象,就只能去分析它的构造了,因为没有其他的地方使用
II. 源码定位
1. 整形传参构造
分析下面这一行, 直接进入源码
BigDecimal origin = new BigDecimal(541253);
复制代码很明显的int传参构造,进去简单看一下
// java.math.BigDecimal#BigDecimal(int)
public BigDecimal(int val) {
this.intCompact = val;
this.scale = 0;
this.intVal = null;
}
public BigDecimal(long val) {
this.intCompact = val;
this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
this.scale = 0;
}
复制代码so,很明确的知道默认的scale为0,也就是说当origin为正数时,以它进行的除法,不现实指定scale参数时,最终返回的都是没有小数的,同样看一眼,还有long的传参方式, BigInteger也一样
2. 浮点传参
接下来就是浮点的scale默认值确认了,这个构造相比前面的复杂一点,源码就不贴了,太长,也看不太懂做了些啥,直接用猥琐一点的方式,进入debug模式,单步执行
@Test
public void testBigDecimal() {
BigDecimal origin = new BigDecimal(541253.0);
BigDecimal now = new BigDecimal(12389431.1);
BigDecimal tmp = new BigDecimal(0.0);
}
复制代码根据debug的结果,第一个,scale为0; 第二个scale为29, 第三个scale为0
3. String传参
依然是一大串的逻辑,同样采用单步debug的方式试下
@Test
public void testBigDecimal() {
BigDecimal origin = new BigDecimal("541253.0");
BigDecimal now = new BigDecimal("12389431.1");
BigDecimal t = new BigDecimal("0.0");
}
复制代码上面三个的scale都是1
4. 小结
- 对于BigDecimal进行除法运算时,最好指定其scale参数,不然可能会有坑
- 对于BigDecimla的scale初始化的原理,有待深入看下BigDecimal是怎么实现的
II. 其他
1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/149837.html原文链接:https://javaforall.cn
边栏推荐
- 【testlink】TestLink1.9.18常见问题解决方法
- C # realizes crystal report binding data and printing 3-qr code barcode
- 兰空图床苹果快捷指令
- EasyX second lesson
- Etcd 构建高可用Etcd集群
- Use JDBC technology and MySQL database management system to realize the function of course management, including adding, modifying, querying and deleting course information.
- Three traversal methods of binary tree
- 深耕5G,芯讯通持续推动5G应用百花齐放
- CMake教程Step3(添加库的使用要求)
- flask解决CORS ERR 问题
猜你喜欢

IDC报告:腾讯云数据库稳居关系型数据库市场TOP 2!

调查显示传统数据安全工具面对勒索软件攻击的失败率高达 60%
Oracle缩表空间的完整解决实例

CMake教程Step1(基本起点)

Error in composer installation: no composer lock file present.

thinkphp3.2.3

How to write a full score project document | acquisition technology

The survey shows that the failure rate of traditional data security tools in the face of blackmail software attacks is as high as 60%

Etcd build a highly available etcd cluster
![[first lecture on robot coordinate system]](/img/3c/af056f0fe68b3244a3dc491ceb291d.png)
[first lecture on robot coordinate system]
随机推荐
The third lesson of EasyX learning
调查显示传统数据安全工具面对勒索软件攻击的失败率高达 60%
C# TCP如何设置心跳数据包,才显得优雅呢?
Detailed explanation of printf() and scanf() functions of C language
【7.7直播预告】《SaaS云原生应用典型架构》大咖讲师教你轻松构建云原生SaaS化应用,难题一一击破,更有华为周边好礼等你领!
The second day of learning C language for Asian people
【性能测试】jmeter+Grafana+influxdb部署实战
High number | summary of calculation methods of volume of rotating body, double integral calculation of volume of rotating body
33:第三章:开发通行证服务:16:使用Redis缓存用户信息;(以减轻数据库的压力)
Browser rendering principle and rearrangement and redrawing
7.Scala类
ECU introduction
First day of learning C language
In depth understanding of redis memory obsolescence strategy
飞桨EasyDL实操范例:工业零件划痕自动识别
Error in compiling libssh2. OpenSSL cannot be found
mysql5.6解析JSON字符串方式(支持复杂的嵌套格式)
C # realizes crystal report binding data and printing 3-qr code barcode
C#实现水晶报表绑定数据并实现打印3-二维码条形码
高数 | 旋转体体积计算方法汇总、二重积分计算旋转体体积