点击上方"IT牧场",选择"设为星标"技术干货每日送达!

来源:https://urlify.cn/naiEva

前言

我们都知道浮点型变量在进行计算的时候会出现丢失精度的问题。如下一段代码:

System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);输出:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

可以看到在Java中进行浮点数运算的时候,会出现丢失精度的问题。那么我们如果在进行商品价格计算的时候,就会出现问题。很有可能造成我们手中有0.06元,却无法购买一个0.05元和一个0.01元的商品。因为如上所示,他们两个的总和为0.060000000000000005。这无疑是一个很严重的问题,尤其是当电商网站的并发量上去的时候,出现的问题将是巨大的。可能会导致无法下单,或者对账出现问题。所以接下来我们就可以使用Java中的BigDecimal类来解决这类问题。

普及一下:

Java中float的精度为6-7位有效数字。double的精度为15-16位。

API

构造器:

构造器                   描述
BigDecimal(int)       创建一个具有参数所指定整数值的对象。
BigDecimal(double)    创建一个具有参数所指定双精度值的对象。
BigDecimal(long)      创建一个具有参数所指定长整数值的对象。
BigDecimal(String)    创建一个具有参数所指定以字符串表示的数值的对象。

函数:

方法                    描述
add(BigDecimal)       BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal)  BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal)  BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal)    BigDecimal对象中的值相除,然后返回这个对象。
toString()            将BigDecimal对象的数值转换成字符串。
doubleValue()         将BigDecimal对象中的值以双精度数返回。
floatValue()          将BigDecimal对象中的值以单精度数返回。
longValue()           将BigDecimal对象中的值以长整数返回。
intValue()            将BigDecimal对象中的值以整数返回。

由于一般的数值类型,例如double不能准确的表示16位以上的数字。

BigDecimal精度也丢失

我们在使用BigDecimal时,使用它的BigDecimal(String)构造器创建对象才有意义。其他的如BigDecimal b = new BigDecimal(1)这种,还是会发生精度丢失的问题。如下代码:

BigDecimal a = new BigDecimal(1.01);
BigDecimal b = new BigDecimal(1.02);
BigDecimal c = new BigDecimal("1.01");
BigDecimal d = new BigDecimal("1.02");
System.out.println(a.add(b));
System.out.println(c.add(d));输出:
2.0300000000000000266453525910037569701671600341796875
2.03

可见论丢失精度BigDecimal显的更为过分。但是使用Bigdecimal的BigDecimal(String)构造器的变量在进行运算的时候却没有出现这种问题。究其原因计算机组成原理里面都有,它们的编码决定了这样的结果。long可以准确存储19位数字,而double只能准备存储16位数字。double由于有exp位,可以存16位以上的数字,但是需要以低位的不精确作为代价。如果需要高于19位数字的精确存储,则必须用BigInteger来保存,当然会牺牲一些性能。所以我们一般使用BigDecimal来解决商业运算上丢失精度的问题的时候,声明BigDecimal对象的时候一定要使用它构造参数为String的类型的构造器。

同时这个原则Effective Java和MySQL 必知必会中也都有提及。float和double只能用来做科学计算和工程计算。商业运算中我们要使用BigDecimal。

而且我们从源码的注释中官方也给出了说明,如下是BigDecimal类的double类型参数的构造器上的一部分注释说明:

* The results of this constructor can be somewhat unpredictable.* One might assume that writing {@codenew BigDecimal(0.1)} in* Java creates a {@code BigDecimal} which is exactly equal to* 0.1 (an unscaled value of 1, with a scale of 1), but it is* actually equal to* 0.1000000000000000055511151231257827021181583404541015625.* This is because 0.1 cannot be represented exactly as a* {@codedouble} (or, for that matter, as a binary fraction of* any finite length).  Thus, the value that is being passed* <i>in</i> to the constructor is not exactly equal to 0.1,* appearances notwithstanding.……* When a {@codedouble} must be used as a source for a* {@code BigDecimal}, note that this constructor provides an* exact conversion; it does not give the same result as* converting the {@codedouble} to a {@code String} using the* {@link Double#toString(double)} method and then using the* {@link #BigDecimal(String)} constructor.  To get that result,* use the {@codestatic} {@link #valueOf(double)} method.* </ol>
public BigDecimal(double val) {this(val,MathContext.UNLIMITED);
}

第一段也说的很清楚它只能计算的无限接近这个数,但是无法精确到这个数。第二段则说,如果要想准确计算这个值,那么需要把double类型的参数转化为String类型的。并且使用BigDecimal(String)这个构造方法进行构造。去获取结果。

正确运用BigDecimal

另外,BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象,由刚才我们所罗列的API也可看出。

在一般开发过程中,我们数据库中存储的数据都是float和double类型的。在进行拿来拿去运算的时候还需要不断的转化,这样十分的不方便。这里我写了一个工具类:

/*** @author: Ji YongGuang.* @date: 19:50 2017/12/14.*/
publicclass BigDecimalUtil {private BigDecimalUtil() {}public static BigDecimal add(double v1, double v2) {// v1 + v2BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.add(b2);}public static BigDecimal sub(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.subtract(b2);}public static BigDecimal mul(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.multiply(b2);}public static BigDecimal div(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));// 2 = 保留小数点后两位   ROUND_HALF_UP = 四舍五入return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);// 应对除不尽的情况}
}

该工具类提供了double类型的基本的加减乘除运算。直接调用即可。

干货分享

最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!

•001:《Java并发与高并发解决方案》学习笔记;•002:《深入JVM内核——原理、诊断与优化》学习笔记;•003:《Java面试宝典》•004:《Docker开源书》•005:《Kubernetes开源书》•006:《DDD速成(领域驱动设计速成)》•007:全部•008:加技术讨论群

近期热文

•瓜子二手车在 Dubbo 版本升级、多机房方案方面的思考和实践•Java12可用新特性一览•聊聊 Java 的几把 JVM 级锁•如何设计一个安全的对外接口?•SQL 性能优化梳理•垃圾回收-实战篇


想知道更多?长按/扫码关注我吧↓↓↓>>>技术讨论群<<<喜欢就点个"在看"呗^_^

Java中的BigDecimal类你了解多少?相关推荐

  1. Java中的BigDecimal类你真的了解吗?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:HikariCP www.jianshu.com/p/c81 ...

  2. Java 中的 BigDecimal 类你了解多少?

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:什么?你还在使用fastjson,性能太差了个人原创+1博客:点击前往,查看更多 作者:HikariCP 链接: ...

  3. 后端:Java中的BigDecimal类你了解多少?

    我们都知道浮点型变量在进行计算的时候会出现丢失精度的问题.如下一段代码: System.out.println(0.05 + 0.01); System.out.println(1.0 - 0.42) ...

  4. Java 中的 BigDecimal,你真的会用吗?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | LanceToBigData 来源 | cnb ...

  5. JAVA基础(12.Java中的常用类String)

    目录 1.前言 2.日期(时间)相关类 2.1 日期类的应用场景 2.1.1Java中的日期相关的几个类 3. Java中的常用类学习方式 3.1 什么是常用类?为什么要学习? 3.2 怎么使用Jav ...

  6. Java中的BigDecimal,你真的会用吗?

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 Forgetting someone doesn't mean never ...

  7. java 中常用的类

    java 中常用的类 Math Math 类,包含用于执行基本数学运算的方法 常用API 取整 l  static double abs(double  a) 获取double 的绝对值 l  sta ...

  8. Java中常用的类及其特点

    Java中的内部类有四种(内部类作用1.封装装类型. 2.直接访问外部类成员. 3.回调.)内部类,方便他们的外部类调用,一般不会被其它类使用,比如事件监听器之类的,外部类刚好继承了一个别的类,如果你 ...

  9. java中的stack类和C++中的stack类的区别

    文章目录 1 java中的stack类和C++中的stack类的区别 1.1 java中的stack类 1.2 C++中的stack类 1.3 分析 不经意间想到了这个问题,存到栈中的是对象的引用,还 ...

最新文章

  1. NumPy迎来重大版本更新
  2. 整合Tomcat和Nginx实现动静态负载均衡
  3. 如何解决类模板的分离编译问题?
  4. java中showconfirmdialog_Java实现超市管理系统(含数据库)
  5. 阿里 异构数据 mysql_异构数据库迁移
  6. springbatch导出mysql数据到外部文件
  7. java 接口返回不带双引号_Java入门:基础知识
  8. Linux C代码获取天气情况
  9. 金洪林:红邦创衣止于至善_品牌-生活时尚_品牌_YOKA时尚网
  10. 金华市电子计算机学校,金华市第十四届中小学生计算机竞赛结果
  11. c 实现走迷宫流程图_C语言实现一个走迷宫小游戏(深度优先算法)
  12. 为什么1KB=1024B,而不等于1000B?
  13. 工具_在线生成安卓证书
  14. 在文件原位置修改文件内容
  15. 牛!Mathematica还能这样用!自己制作马赛克拼图
  16. FTPrush给Linux上传文件,LINUX CENTOS 7安装FTP服务器详细讲解(配图),FTPRUSH连接上传测试文件...
  17. Gatsby 中怎么加载使用视频文件?
  18. python取列表中位数_在Python中查找列表的中位数
  19. 20行python代码的入门级小游戏
  20. 创建WinPE启动盘、常用imagex指令、常用dism指令

热门文章

  1. Cocos Creator 下载图片动态替换纹理
  2. elasticsearch DSL查询之should查询
  3. 调用百度API 报错:Open api qps request limit reached
  4. 怎么退出自适应巡航_吉利ICON ACC自适应巡航系统
  5. 每周一磁 · 矫顽力Hcb和内禀矫顽力Hcj
  6. [Swift]LeetCode1108. IP 地址无效化 | Defanging an IP Address
  7. python数据可视化(matplotlib,seaborn,plotly)
  8. vulnhub靶场-Hacker_Kid-v1.0.1
  9. C语言n番战--共用体和枚举(八)
  10. javaScript 结构算法刷题 数组题