阿里巴巴为什么建议使用BigDecimal进行浮点数运算
本文先引入一个例子,星期天你和女朋友去逛街,看到一家奶茶店。女朋友想喝奶茶了,你就去买了杯奶茶,然后你问了一下价格。店员说奶茶0.9元一杯。然后你给了1元钱。这个时候你忽然问了一下女友。服务员该找我们多少钱呢?女友说你个小傻瓜当然是0.1元啊。作为一个”严谨“的程序猿,这时你拿起电脑写了个简单计算如下:

看到计算结果不是0.1这个时候你有点慌了,女朋友怎么会错呢?但是你没有犹豫女朋友说的怎么会错呢,女朋友说的一定是对的。一定是电脑计算错了,然后你毫不犹豫把电脑扔了。说了一句对对对该找0.1元。【PS奶茶目前当然不可能1元钱,本文为了演示计算效果所以定义奶茶1元,因为不是所有的浮点运算都会有这样的问题】。
千万别小看这些一点点的计算误差,假如我说假如全国人民一人送你0.1元你能实现财富自由了【呸,别做白日梦了好好搬砖去吧】
好了聊文章的主题BigDecimal这个知识点,这个知识点应该很多人都知道了,我感觉很有有用就聊一下。阿里巴巴开发手册中提到:
使用BigDecimal来定义值,再进行浮点数的运算操作。
注意:BigDecimal(double)存在精度损失的风险,在精确计算或比较的场景中可能会导致业务逻辑异常。如:BigDecimal g = new BigDecimal(0.1f)。实际存储的值为:0.10000000149011611938 。
float a = 1.0f -0.9f;
float b = 0.9f-0.8f ;
System.out.println(a);
System.out.println(b);
System.out.println(a==b);

为什么浮点数 float 或 double 运算的时候会有精度丢失的风险呢?
这个和计算机保存浮点数的机制有很大关系。我们知道计算机是二进制的,而且计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。
那怎么解决精度丢失的问题呢?那就是本文要说的BigDecimal。用它可以实现对浮点的计算,解决精度丢失的问题。如下用差不多相同的代码结果就是对的【PS一定要记住女朋友说的就是对的就是0.1】。

BigDecimal创建方法,请先看注意事项:
阿里官方:【强制】禁止使用构造方法BigDecimal(double)的方式把double值转换为BigDecimal对象
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = BigDecimal.valueOf(0.1);
开发中用到计算也就是加减乘除,BigDecimal中相关方法如下:
add 方法用于将两个 BigDecimal 对象相加。subtract 方法用于将两个 BigDecimal 对象相减。multiply 方法用于将两个 BigDecimal 对象相乘,divide 方法用于将两个 BigDecimal 对象相除。

这里需要注意的是,在我们使用 divide 方法的时候尽量使用 3 个参数方法。其中 scale 表示要保留几位小数,roundingMode 代表保留规则。具体可以看源码,源码中介绍的很清楚了,并且给了各种例子如下:

大小的比较
a.compareTo(b) : 返回 -1 说明 a 小于 b,0 说明a 等于 b , 1 说明 a 大于 b。用法如下:

注意:BigDecimal的比较不能使用equals进行比较【原因还是因为精度的问题】,一定要使用compareTo比较,如下:

BigDecilmal计算相关的工具类。
add方法:
public static BigDecimal add(Number v1, Number v2) {
return add(new Number[]{v1, v2});
}
public static BigDecimal add(Number... values) {
if (ArrayUtil.isEmpty(values)) {
return BigDecimal.ZERO;
}
Number value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
result = result.add(new BigDecimal(value.toString()));
}
}
return result;
}
substract方法:
public static BigDecimal sub(Number v1, Number v2) {
return sub(new Number[]{v1, v2});
}
public static BigDecimal sub(Number... values) {
if (ArrayUtil.isEmpty(values)) {
return BigDecimal.ZERO;
}
Number value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
result = result.subtract(new BigDecimal(value.toString()));
}
}
return result;
}
multiply 乘法:
public static BigDecimal mul(Number v1, Number v2) {
return mul(new Number[]{v1, v2});
}
public static BigDecimal mul(Number... values) {
if (ArrayUtil.isEmpty(values)) {
return BigDecimal.ZERO;
}
Number value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
for (int i = 1; i < values.length; i++) {
value = values[i];
result = result.multiply(new BigDecimal(null == value ? "0" : value.toString()));
}
return result;
}
divide 除法:
public static BigDecimal div(BigDecimal v1, BigDecimal v2,Integer scale,RoundingMode roundingMode) {
if (null == v1) {
return BigDecimal.ZERO;
}
if (scale < 0) {
scale = -scale;
}
return v1.divide(v2, scale, roundingMode);
}
谢谢点赞,也欢迎你分享给其他的开发者,让更多的人知道。当然也欢迎未关注的小伙伴关注。

阿里巴巴为什么建议使用BigDecimal进行浮点数运算的更多相关文章
- 浮点数运算结果不精确,以及用String来构造BigDecimal进行浮点数精确计算
1.浮点数运算结果不精确 先看如下代码 System.out.println(1.0 - 0.8); System.out.println(0.2 + 0.1); System.out.println ...
- BigDecimal - Java精确运算
(1).浮点数精确计算 项目中一直存在一个问题,就是每次报表统计的物资金额和实际的金额要差那么几分钱,和实际金额不一致,让客户觉得总是不那么舒服,原因是因为我们使用java的浮点类型double来定义 ...
- js,java,浮点数运算错误及应对方法
js,java浮点数运算错误及应对方法 一,浮点数为什么会有运算错误 IEEE 754 标准规定了计算机程序设计环境中的二进制和十进制的浮点数自述的交换.算术格式以及方法. 现有存储介质都是2进制.2 ...
- 使用BigDecimal进行精确运算
首先我们先来看如下代码示例: 1 public class Test_1 { 2 public static void main(String[] args) { 3 System.out.print ...
- 使用Java BigDecimal进行精确运算
首先我们先来看如下代码示例: public class Test_1 { public static void main(String[] args) { System.out ...
- (转)使用BigDecimal进行精确运算
场景:在进行支付业务的金额计算时,通常采用BigDecimal类型的数据,并没有看到常见的int double类型,所以有必要好好学习下BigDecimal的常用用法. 1 误区 首先我们先来看如下代 ...
- 电商网站中价格的精确计算(使用BigDecimal进行精确运算(实现加减乘除运算))
使用BigDecimal的String的构造器.商业计算中,使用bigdecimal的String构造器,一定要用. 重要的事情说三遍: 商业计算中,使用bigdecimal的String构造器! 商 ...
- BigDecimal进行精确运算demo工具类
package com.js.ai.modules.pointwall.interfac; import java.math.BigDecimal; public class TestDigDecim ...
- BigDecimal进行精确运算
public class Test_1 { public static void main(String[] args) { System.out.println(0.06+0.01); System ...
- 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 确的浮点数运算,包括加减乘除和四舍五入。
package com.minxinloan.utils; import java.math.BigDecimal; public class Arith { // 源文件Arith.java: /* ...
随机推荐
- OOP前三次作业总结
一.前言 在开始OOP学习之前,我从未了解过什么是面向对象编程,想当然的认为OOP是像从前学习C一样的编程逻辑(即面向过程编程),但在真正开始学习OOP之后,我了解到了以往面向过程编程的局限性与不便利 ...
- uiautomator2自动化工具的下载与安装
前言: 相信很多使用appium做过APP自动化的人都深有感触: 1,安装麻烦,配置环境可能会难道不少人 2,appium运行慢.时间长 3,uiautomatorviewer定位元素时得关掉appi ...
- CPU密集型和IO密集型与线程池的配置
CPU密集型任务应配置尽可能小的线程,如配置CPU数目+1个线程的线程池.由于IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*CPU数目.
- vue表单校验限制输入数字后小数点两位(包括避开通过中文输入法的那些坑)
<el-form-item label="海运运费系数"> <el-input v-model.trim="ruleForm.oceanFreightC ...
- https://计算机四级
计算机四级内容: 一,网络工程师 基本要求 1.了解大型网络系统规划.管理方法: 2.具备中小型网络系统规划.设计的基本能力: 3.掌握中小型网络系统组建.设备配置调试的基本技术: 4.掌握企事业单位 ...
- python之变量
什么是变量? 用来记录事务的变化状态,计算机模拟人,就需要具备人类某一个功能.你通过记录我的名字年龄等一系列的身份信息,以此和我进行匹配,确定我就是phoebe这个人. 为什么有变量? 游戏里的英雄角 ...
- [jmeter的使用]jmeter上传文件接口的写法
1.类型和参数名称,依据接口/抓的包决定 2.必须选择java否则报错 3.http header也要写
- mybatis的sql操作
1.Mapper接口创建 创建Mapper包,所有的Mapper接口放在该包下.Mapper接口中声明将要实现的方法,在接下来的Mapper.xml文件中实现对应方法. 2.Mapper.xml创建 ...
- springboot启动图标banner
将springboot项目中的banner.txt文件替换成下面代码即可 ${AnsiColor.BRIGHT_YELLOW} ┏━┓ ┏━┓ ┏┛ ┻━━━━━┛ ┻┓ ┃ ┃ ┃ ━ ┃ ┃ ┳┛ ...
- springboot整合mybatis:查询语句,返回null
springboot整合mybatis时,查询数据库数据时,返回结果为null; 刚开始以为是数据库没连接上,结果增.改.删的其他语句则执行成功: 但唯有查询语句始终返回null,一条数据一个null ...