BigDecimal使用注意避坑
创始人
2024-05-26 06:47:58
0

目录

  • 一. BigDecimal的初始化精度丢失问题
  • 二. BigDecimal在进行除法运算时需设置精度,否则对于除不尽的情况会抛出异常
  • 三. 不要使用BigDecimal的equals方法比较大小, 否则可能会因为精度问题导致比较结果和预期的不一致

在java.math包中提供了对大数字的操作类,用于进行高精确计算,如BigInteger,BigDecimal类。而平常我们开发中使用最多的float和double只能适用于一般的科学和工程计算,如果要在比较精确的计算方面如货币,那么使用float和double会相应的丢失精度,因此用于精密计算大数字的类BigDecimal就必不可少了。所以BigDecimal适合商业计算场景,用来对超过16位有效位的数进行精确的运算。但是BigDecimal的使用并不像float和double那样,使用不当造成的后果更严重,下面就来看下我们项目中踩过BigDecimal的坑:

一. BigDecimal的初始化精度丢失问题

先来看下面代码的运行结果:

BigDecimal bd1 = new BigDecimal(0.1);
System.out.println("bd1="+bd1);
BigDecimal bd2 = new BigDecimal("0.1");
System.out.println("bd2="+bd2);
BigDecimal bd3 = BigDecimal.valueOf(0.1);
System.out.println("bd3="+bd3);

输出结果:

bd1=0.1000000000000000055511151231257827021181583404541015625
bd2=0.1
bd3=0.1

如果是float或double类型转Bigdecimal,不要使用new BigDecimal()转, 使用valueOf()方法 或 new BigDecimal(“”)转成string,否则有可能出现精度问题。

《Effective Java》这本书里说过:
如果需要精确的答案,请避免使用float和double

因为float和double执行的是二进制浮点运算,二进制有些情况下不能准确的表示一个小数,就像十进制不能准确的表示1/3(1/3=0.3333…)也就是说二进制表示小数的时候只能够表示能够用1/(2^n)的和的任意组合,例如:

  • 0.5能够表示,因为它可以表示成为1/2
  • 0.75也能够表示,因为它可以表示成为1/2+1/(2^2)
  • 0.875也能够表示,因为它可以表示成为1/2+1/(22)+1/(23)
  • 但是0.1不能够精确表示,因为它不能够表示成为1/(2^n)的和的形式
System.out.println(0.5*3);
System.out.println(0.1*3);

大家可以本地执行下这两行代码,看下输出结果就知道为什么二进制不能表示0.1却可以表示0.5了。所以其实不是BigDecimal的问题,BigDecimal就是为了满足精确运算存在的,问题出在0.1它本身就一个不准确的值,这其实跟BigDecimal无关,但在使用的时候需要注意用法。

二. BigDecimal在进行除法运算时需设置精度,否则对于除不尽的情况会抛出异常

继续看下面的代码执行结果:

BigDecimal bd4 = new BigDecimal("10");
BigDecimal bd5 = new BigDecimal("3");
System.out.println(bd4.divide(bd5));

输出结果:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1690)
at BigDecimalTest.main(BigDecimalTest.java:38)

应该向下面这样设置小数点后的位数,以及超出后是四舍五入和向上/向下取整或者直接舍弃:

System.out.println(bd4.divide(bd5,2,BigDecimal.ROUND_DOWN));

第二个参数表示小数位数,第三个参数表示超出的位数直接舍弃(当然也可以设置四舍五入,向上取整等)

三. 不要使用BigDecimal的equals方法比较大小, 否则可能会因为精度问题导致比较结果和预期的不一致

BigDecimal bd1 = new BigDecimal("0");
BigDecimal bd2 = new BigDecimal("0.0");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2) == 0)

输出结果:

equals:false
compareTo:true

如果你无法确定你的BigDecimal值有小数情况,最好用compareTo!

相关内容

热门资讯

为什么一听到声音就特别烦躁,有... 为什么一听到声音就特别烦躁,有时候还会控制不住想哭?是不是你最近压力太大了?去看看心理医生吧。要不然...
有没有知道名家描写四季的文章? 有没有知道名家描写四季的文章?只要是家描写四季的文章都行,大家帮找找吧~最好是夏天和冬天的~大家帮帮...
学习计划书的格式 学习计划书的格式急急急急急啊学习计划书格式分三块:1.学习计划书名称仔细回顾一下自己的学习情况,找出...
四年级下册暑假生活指导参考答案... 四年级下册暑假生活指导参考答案山东教育出版社(英语)是2011年的 是帮助tony闯关的。急急...
《翼年代记之东京默示录》主要讲... 《翼年代记之东京默示录》主要讲什么的讲的就是故事讲小樱及小狼来自玖楼国(在日文中,《魔卡少女樱》的大...
纪晓岚简介 纪晓岚简介 纪昀(jǐ yún),字晓岚,一字春帆,晚号石云,道号观弈道人。生于清雍正二年(17...
昨天买的奶茶今天有了一点沉淀物... 昨天买的奶茶今天有了一点沉淀物,还有一点酸味,还吃得了吗?如果你买的不是酸奶最好是不要吃了!这么热的...
冲熬是什么意思 冲熬是什么意思冲熬是什么意思封建迷信的意思
实木家具油漆工艺流程 实木家具油漆工艺流程实木家具刷油漆的方法步骤:第一步,卸把手等装饰品,为了防止把手等饰品沾上油漆,刷...
我想买一台收音机给我奶奶,请问... 我想买一台收音机给我奶奶,请问大家什么电台最适合老人听?最好是没有医学专家讲座的电台。谢谢各位了! ...
寻找儿时的味道!! 寻找儿时的味道!!小时候吃过一种火锅蘸料,别人送的,说是四川的,很麻!吃完嘴巴没感觉那种,不是辣!有...
巢毁卵破的意思是什么,出处是哪... 巢毁卵破的意思是什么,出处是哪里?cháo huǐ luǎn pò成语释义 鸟巢毁了,卵也一定会打...
美好的反义词是什么 标准答案 美好的反义词是什么 标准答案美好【近义词】优美 美妙 美丽 俊美【反义词】丑恶 丑陋丑恶糟糕...
西西里岛有哪些经典值得推荐? 西西里岛有哪些经典值得推荐?我觉得陶尔米纳小城商业气息异常浓重, 基本就是一个为了旅游而生的小城, ...
股评,下跌能量不足,观望.是什... 股评,下跌能量不足,观望.是什么意思就是说某个股票,价格已经下降,但并没有放量下跌,请观望。意思是说...
请你留下请你别走请你留下我的朋... 请你留下请你别走请你留下我的朋友就算要走也请稍停留天空下雨天留我也留 ,这首歌名是什么?就是,请你留...
考研小作文写跑题了 但格式字数... 考研小作文写跑题了 但格式字数都对 能多少分应该是只能得8分
大学生的新一年工作计划书怎么写 大学生的新一年工作计划书怎么写 
星空卫视的动画片 星空卫视的动画片星空卫视2004年到2007年(具体哪一年我也忘记了)播的一部动画片 里面的鬼跟主人...
猴子吃香蕉 猴子吃香蕉有只猴子在树林里采了100根香蕉堆成一堆,猴子家离香蕉堆50米,猴子打算把香蕉背回家,每次...