点击上方 好好学java ,选择 星标 公众号

重磅资讯、干货,第一时间送达
今日推荐:什么?你还在使用fastjson,性能太差了个人原创+1博客:点击前往,查看更多
作者:HikariCP
链接:https://www.jianshu.com/p/c81edc59546c

前言

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

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 {@code new 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* {@code double} (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 {@code double} 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 {@code double} 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 {@code static} {@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.*/
public class 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类型的基本的加减乘除运算。直接调用即可。

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

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

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

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

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

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

    点击上方"IT牧场",选择"设为星标"技术干货每日送达! 来源:https://urlify.cn/naiEva 前言 我们都知道浮点型变量在进行计算的时候会出 ...

  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. 第五百七十二、三天 how can I 坚持
  2. Linux 平台一种进程代码注入方法
  3. python中类的嵌套_python中的嵌套类 | 学步园
  4. 乡村振兴国际经验-农民丰收节贸易会: 谋定城镇化进程
  5. 图像算法处理视频不稳定?港科大团队提出一种通用算法解决视频处理时域不稳定问题
  6. 实验四---继承与派生练习以及运算符[ ]重载练习
  7. Android中Log信息的输出方法
  8. ASP.NET Core中Ocelot的使用:基于服务发现的负载均衡
  9. 泰禾光电机器人研发_机器之眼 | 3D相机能让机器人看见什么?
  10. 高二女生制作危险驾驶报警手机软件
  11. Matlab与Access数据库的连接
  12. arduino的矩阵示例程序_用树莓派 Arduino 制造 LED 矩阵彩灯
  13. ROS-Academy-for-Beginners之ORB-SLAM2 双目视觉初探
  14. 数据库基础(3)函数依赖-平凡依赖,完全依赖,部分依赖,传递依赖
  15. 软件测试的底层逻辑是什么?
  16. navicat超时未激活如何处理?
  17. 关于word不能存档解决办法
  18. liferay mysql_Liferay学习笔记(一)Liferay Portal5.2.3环境的初步搭建
  19. 四柱八字大全 php,四柱八字查询表 免费四柱八字查询
  20. 广州楼市:400W,高升值潜力的热门板块!

热门文章

  1. ESP8266/ESP32 NVS 基本操作
  2. linux内核之 phys_to_virt
  3. 跨链Cosmos(8)同构跨链交易流程
  4. Exclusive monitor在spinlock中的应用
  5. 10-Armv8-A memory model guide
  6. Fabric--启动网络手动
  7. md5加密算法原理及其GO语言实现
  8. 种群计数 (pop_count)
  9. TLS调试检测和反调试
  10. 汇编中的通用寄存器、标志寄存器、段寄存器