为什么要有BigDecimal ,他是干什么的

float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。但是,商业计算往往要求结果精确,这时候就要使用BigDecimal啦。

什么是BigDecimal

BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负scale 次幂。因此,BigDecimal表示的数值是(unscaledValue × 10-scale)。

本文将给大家详细介绍关于Java中BigDecimal精度和相等比较的坑,下面话不多说了,来一起看看详细的介绍吧

先想一下,创建BigDecimal对象的时候一般是怎么创建的?

new一个,传进去值

BigDecimal.valueOf方法,传进去值

作为一个数字类型,经常有的操作是比较大小,有一种情况是比较是否相等。用equal方法还是compareTo方法?这里就是一个大坑

//new 传进去一个double

BigDecimal newZero = new BigDecimal(0.0);

System.out.println(BigDecimal.ZERO.equals(newZero));

//new 传进去一个字符串

BigDecimal stringNewZero = new BigDecimal("0.0");

System.out.println(BigDecimal.ZERO.equals(stringNewZero));

//valueOf 传进去一个double

BigDecimal noScaleZero = BigDecimal.valueOf(0.0);

System.out.println(BigDecimal.ZERO.equals(noScaleZero));

//valueOf 传进去一个double,再手动设置精度为1

BigDecimal scaleZero = BigDecimal.valueOf(0.0).setScale(1);

System.out.println(BigDecimal.ZERO.equals(scaleZero));

用于比较的值全都是0,猜一猜上面几个equals方法返回的结果是什么?全都是true?no no no...

true

false

false

false

惊不惊喜,意不意外?原因是什么呢?看一下BigDecimal的equals方法的实现:

public boolean equals(Object x) {

//类型不同,直接返回false

if (!(x instanceof BigDecimal))

return false;

BigDecimal xDec = (BigDecimal) x;

//同一个对象,直接返回true

if (x == this)

return true;

//精度不同,直接返回false!!

if (scale != xDec.scale)

return false;

long s = this.intCompact;

long xs = xDec.intCompact;

if (s != INFLATED) {

if (xs == INFLATED)

xs = compactValFor(xDec.intVal);

return xs == s;

} else if (xs != INFLATED)

return xs == compactValFor(this.intVal);

return this.inflated().equals(xDec.inflated());

}

从前面三个简单的判断就可以看出来,debug跟一下就知道是上面equals方法有三个返回false,都是因为精度不同。那么BigDecimal.ZERO的精度是多少呢?看下源码:

// Cache of common small BigDecimal values.

private static final BigDecimal zeroThroughTen[] = {

new BigDecimal(BigInteger.ZERO, 0, 0, 1),

new BigDecimal(BigInteger.ONE, 1, 0, 1),

new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),

new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),

new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),

new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),

new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),

new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),

new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),

new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),

new BigDecimal(BigInteger.TEN, 10, 0, 2),

};

/**

* The value 0, with a scale of 0.

*

* @since 1.5

*/

public static final BigDecimal ZERO = zeroThroughTen[0];

BigDecimal.ZERO值为0,精度为0.

而上面几种返回false的case,都是因为精度不同。精度不同的原因,则是BigDecimal对象初始化的方式不同,从源码上看,前三种初始化的方式都不同。

所以说,BigDecimal比较大小,还是用compareTo方法比较靠谱,改为compareTo之后,上面四个case返回的结果都是相等:

BigDecimal newZero = new BigDecimal(0.0);

System.out.println(BigDecimal.ZERO.compareTo(newZero));

BigDecimal stringNewZero = new BigDecimal("0.0");

System.out.println(BigDecimal.ZERO.compareTo(stringNewZero));

BigDecimal noScaleZero = BigDecimal.valueOf(0.0);

System.out.println(BigDecimal.ZERO.compareTo(noScaleZero));

BigDecimal scaleZero = BigDecimal.valueOf(0.0).setScale(1);

System.out.println(BigDecimal.ZERO.compareTo(scaleZero));

输出结果

0

0

0

0

由此联想到的一个更大的坑是,如果将BigDecimal的值作为HashMap的key,因为精度的问题,相同的值就可能出现hashCode值不同并且equals方法返回false,导致put和get就很可能会出现相同的值但是存取了不同的value。

再想一想,小数类型在计算机中本来就不能精确存储,再把其作为HashMap的key就相当不靠谱了,以后还是少用。

另外需要注意的一点是,写代码调别人写的方法时,最好是点进去看一下实现。再小再常用的方法,都可能埋着大坑

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

本文标题: Java中BigDecimal精度和相等比较的坑

本文地址: http://www.cppcns.com/ruanjian/java/239730.html

bigdecimal 和负数比较_Java中BigDecimal精度和相等比较的坑相关推荐

  1. bigdecimal取小数部分_Java中BigDecimal保留两位小数点有哪些方法

    Java中BigDecimal保留两位小数点有哪些方法?今天就跟长沙尚学堂小编一起来好好的了解下,到底有哪些方法,希望你至少能够掌握好一种. 保留两位小数{ 方法一:{ double c=3.1542 ...

  2. java bigdecimal赋值_Java中BigDecimal类介绍及用法(亲测)

    Java中提供了大数字(超过16位有效位)的操作类,即 java.math.BinInteger 类和 java.math.BigDecimal 类,用于高精度计算. 其中 BigInteger 类是 ...

  3. java 浮点数精度_Java中浮点数精度问题

    Java中浮点数精度问题 Java中的简单浮点数类型float和double不能够进行运算.不光是Java,在其它很多编程语言中也有这样的问题.如下图所示: public class DataRang ...

  4. bigdicmal除法精度设置_java中BigDecimal进行加减乘除的基本用法

    前言 众所周知Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或 ...

  5. java中multiply用法_java中BigDecimal加减乘除基本用法

    Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数. 在实际应用中,需要对更大或者更小的数进 ...

  6. java divide 用法_java中BigDecimal加减乘除基本用法

    Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数. 在实际应用中,需要对更大或者更小的数进 ...

  7. java 中subtract的用法_java中BigDecimal加减乘除基本用法

    Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数. 在实际应用中,需要对更大或者更小的数进 ...

  8. java 舍_Java中BigDecimal的8种舍入模式

    java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成. 如果为零或正数,则标度是小数点后的位 ...

  9. java bigdecimal 开方_在Java中BigDecimal的平方根(Square root of BigDecimal in

    我们可以计算平方根BigDecimal仅使用的Java API而不是定制的100线算法在Java中? Answer 1: 我用这个和它的作品相当不错的. 下面是该算法如何工作在较高水平的例子. 编辑: ...

最新文章

  1. Android的开发
  2. jQuery1.8 css模块评析
  3. 2020年春季学期信号与系统课程作业参考答案-第十三次作业
  4. 【Thread】简单说说java.lang.Thread.State
  5. 最新综述:多标签学习的新趋势
  6. OpenCV3学习(2.1)——图像Mat数据的访问-at/ptr/iterator
  7. 深圳人才引进,大学生,公司的福利
  8. 12.go 源码文件
  9. php exeil导入,反编译工具ILSpy.exe
  10. 周记——20151123
  11. python从1加到100的其中两种方式
  12. iReport表达式
  13. 获取指定年份的工作日和节假日后导入Excel
  14. 华南师大计算机转专业,广西师范大学计算机科学与信息工程学院/软件学院转专业管理规定(试行)...
  15. Flutter最新开源框架,工作感悟
  16. 杰瑞学Perl之文件操作(1)
  17. Redis( 缓存篇 ==> 互斥锁解决缓存击穿
  18. Libp2p - IPFS 与 Polkadot :双剑合璧会有时
  19. 【二叉树的前序、中序、后序遍历的python写法】借助栈的实现,效率媲美递归~
  20. STM32G431—ADC+E2PROM读写实验

热门文章

  1. linux chattr与lsattr命令 底层权限控制
  2. python3 request模块 https certificate verify failed 错误
  3. linux awk 多分隔符
  4. nmap脚本(nse)原理和编写
  5. 深入理解 C 指针阅读笔记 -- 第一章
  6. 编程之美2.8 找符合条件的整数
  7. windows7怎么安装python库_如何在Windows 7安装Python2.7
  8. php语言smtp类,php mailer类调用远程SMTP服务器发送邮件实现方法
  9. php样式无法加载 路径对的,网站首页 有时加载不了样式
  10. oracle asm dd命令,使用dd命令复制ASM磁盘的spfile