BigDecimal 介绍

BigDecimal 可以实现对浮点数的运算,不会造成精度丢失。

通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的。

《阿里巴巴 Java 开发手册》中提到:浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能用 equals 来判断。

具体原因我们在上面已经详细介绍了,这里就不多提了。

想要解决浮点数运算精度丢失这个问题,可以直接使用 BigDecimal 来定义浮点数的值,然后再进行浮点数的运算操作即可。

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);System.out.println(x.compareTo(y));// 0

BigDecimal 常见方法

创建

我们在使用 BigDecimal 时,为了防止精度丢失,推荐使用它的BigDecimal(String val)构造方法或者 BigDecimal.valueOf(double val) 静态方法来创建对象。

《阿里巴巴 Java 开发手册》对这部分内容也有提到,如下图所示。

加减乘除

add 方法用于将两个 BigDecimal 对象相加,subtract 方法用于将两个 BigDecimal 对象相减。multiply 方法用于将两个 BigDecimal 对象相乘,divide 方法用于将两个 BigDecimal 对象相除。

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.add(b));// 1.9
System.out.println(a.subtract(b));// 0.1
System.out.println(a.multiply(b));// 0.90
System.out.println(a.divide(b));// 无法除尽,抛出 ArithmeticException 异常
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP));// 1.11

这里需要注意的是,在我们使用 divide 方法的时候尽量使用 3 个参数版本,并且RoundingMode 不要选择 UNNECESSARY,否则很可能会遇到 ArithmeticException(无法除尽出现无限循环小数的时候),其中 scale 表示要保留几位小数,roundingMode 代表保留规则。

public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {return divide(divisor, scale, roundingMode.oldMode);
}

保留规则非常多,这里列举几种:

public enum RoundingMode {// 2.5 -> 3 , 1.6 -> 2// -1.6 -> -2 , -2.5 -> -3UP(BigDecimal.ROUND_UP),// 2.5 -> 2 , 1.6 -> 1// -1.6 -> -1 , -2.5 -> -2DOWN(BigDecimal.ROUND_DOWN),// 2.5 -> 3 , 1.6 -> 2// -1.6 -> -1 , -2.5 -> -2CEILING(BigDecimal.ROUND_CEILING),// 2.5 -> 2 , 1.6 -> 1// -1.6 -> -2 , -2.5 -> -3FLOOR(BigDecimal.ROUND_FLOOR),// 2.5 -> 3 , 1.6 -> 2// -1.6 -> -2 , -2.5 -> -3HALF_UP(BigDecimal.ROUND_HALF_UP),//......
}

大小比较

a.compareTo(b) : 返回 -1 表示 a 小于 b,0 表示 a 等于 b , 1 表示 a 大于 b

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.compareTo(b));// 1

保留几位小数

通过 setScale方法设置保留几位小数以及保留规则。保留规则有挺多种,不需要记,IDEA 会提示。

BigDecimal m = new BigDecimal("1.255433");
BigDecimal n = m.setScale(3,RoundingMode.HALF_DOWN);
System.out.println(n);// 1.255

BigDecimal 等值比较问题

《阿里巴巴 Java 开发手册》中提到:

BigDecimal 使用 equals() 方法进行等值比较出现问题的代码示例:

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.equals(b));//false

这是因为 equals() 方法不仅仅会比较值的大小(value)还会比较精度(scale),而 compareTo() 方法比较的时候会忽略精度。

1.0 的 scale 是 1,1 的 scale 是 0,因此 a.equals(b) 的结果是 false。

compareTo() 方法可以比较两个 BigDecimal 的值,如果相等就返回 0,如果第 1 个数比第 2 个数大则返回 1,反之返回-1。

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.compareTo(b));//0

总结

浮点数没有办法用二进制精确表示,因此存在精度丢失的风险。

不过,Java 提供了BigDecimal 来操作浮点数。BigDecimal 的实现利用到了 BigInteger (用来操作大整数), 所不同的是 BigDecimal 加入了小数位的概念。

使用 BigDecimal 进行浮点数运算相关推荐

  1. bigdicmal除法精度设置_Java BigDecimal浮点数运算--如何保证运算精度不溢出

    加减乘除四则运算是高级程序设计语言(不论机器语言.汇编还是其他高级语言)最基础的部分,Java作为最流行的软件开发语言之一,涉及四则运算的程序代码和功能业务随处可见.在笔者从事的基于Java语言银行. ...

  2. Java中使用BigDecimal进行浮点数精确计算 超大整数 浮点数等计算,没有数位限制...

    (注:前面写了一个超大整数相加的类,参见: 超大整数相加,超过了long的范围,你要怎么做!,后来有朋友评论说BigDecimal可以完全实现我的这这个功能,刚开始的时候,我还不服气,据我所知那里有这 ...

  3. 使用BigDecimal进行精确运算

    首先我们先来看如下代码示例: 1 public class Test_1 { 2 public static void main(String[] args) { 3 System.out.print ...

  4. Java中使用BigDecimal进行浮点数精确计算 超大整数 浮点数等计算 没有数位限制

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! (注:前 ...

  5. 关于Java浮点数运算精度丢失问题

    2019独角兽企业重金招聘Python工程师标准>>> 关于Java浮点数运算精度丢失问题 博客分类: java 前几天看了一个朋友的博客,说Java中浮点数运算精度丢失的问题,他给 ...

  6. 详解BigDecimal及其加减乘除运算

    目录 一.BigDecimal概述 二.构造函数详解 1.BigDecimal(int val) 2.BigDecimal(int val, MathContext mc) MathContext 3 ...

  7. 浮点数的输入以及浮点数运算

    浮点数的输入以及浮点数运算 写在前面 上一次我们讲解了IEEE的标准,还记得多少? 之前我提到过,有很多小数是二进制浮点数无法表示的,因此就难免会遇到舍入的问题.这一点其实在我们平时的计算当中会经常出 ...

  8. java 浮点数运算_对于同样的浮点数运算为何 Java 与 C 的结果不相同?

    @bombless 在问题的评论里写得没错.IEEE 754最重要的(大家基本上遵守的)是数据的格式.虽然也有算法上的指引(例如有各种rounding mode),但实际上大家实现得不一定那么严格. ...

  9. Java浮点数运算工具类

    import java.math.BigDecimal; import java.math.RoundingMode;/*** 精确的浮点数运算*/ public class Arith {/** 默 ...

最新文章

  1. awk截取字符命令_Linux运维基础技能: 脚本编程与Linux命令
  2. NIO源码解析:IntBuffer基本使用
  3. Nginx域名访问与访问控制
  4. 钱荒下银行理财收益率角逐:邮储银行垫底
  5. gc.collect()==>python的强制垃圾收集机制(不建议使用强制回收,因为可能导致错误)
  6. 程序—java年月日转换
  7. Objcet_类的方法
  8. AcWing 904. 虫洞(SPFA or Djakarta or bellman判负环)
  9. vsan双主机配置_5千右预算,兼顾Pr剪辑、Ps修图、CAD制图的高性价比DIY主机配置...
  10. pythonint函数的参数_pythonint函数怎么用
  11. 谷歌大脑科学家 Caffe缔造者 贾扬清 微信讲座
  12. Springboot配置devtools实现热部署
  13. VS2012更改/重置默认开发环境
  14. MPU6050配置低功耗和中断
  15. CCNA2.0笔记_动态路由
  16. gitalk 未找到相关的Issues进行评论解决方法
  17. 您访问的网页出错了!
  18. Mapper代理文件实现
  19. 等保测评方案怎么做?按照这个流程来,轻松又省心!
  20. TCP/IP滑动窗口

热门文章

  1. 农村大学生的逆袭009
  2. Windows快捷键---原创总结zyh
  3. android手机如何拥有苹果表情包,安卓手机emoji表情怎么改成苹果的
  4. VC2017编译zxing
  5. 实践检验递归查询SQL
  6. traceback.print_exc()跟traceback.format_exc()有什么区别
  7. 神经网络和贝叶斯网络关系
  8. Object isExtensible()方法
  9. 【电子学会】2021年06月图形化二级 -- 小瓢虫找妈妈
  10. U盘安装win10时,出现“Windows无法打开所需文件D:\Sources\install.wim”解决办法