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!

相关内容

热门资讯

隔夜要闻:美股收高 穆迪下调美...   欲览更多环球财经资讯,请移步7×24小时实时财经新闻  市场  收盘:本周标普指数上涨5.3% ...
诚志股份有限公司关于参加江西辖... 证券代码:000990 证券简称:诚志股份 公告编号:2025-025诚志股份有限公司关于参加江西...
哈尔滨新光光电科技股份有限公司... 证券代码:688011 证券简称:新光光电 公告编号:2025-18哈尔滨新光光电科技股份有限公司...
黑土地充满投资吸引力 转自:黑龙江日报 □本报记者 孙铭阳 “我切身感受到,黑龙江正在开启高质量发展、可持续...
昱能科技股份有限公司关于董事会... 证券代码:688348 证券简称:昱能科技 公告编号:2025-023昱能科技股份有限公司关于董事...
太平洋证券股份有限公司诉讼进展...   炒股就看金麒麟分析师研报,权威,专业,及时,全面,助您挖掘潜力主题机会! 证券代码:60109...
智慧养老前景可期 可穿戴设备收集健康数据、毫米波雷达识别跌倒情况、虚拟养老院提供照料服务……近年来,随着物联网、人工智...
张家港保税科技(集团)股份有限... 证券代码:600794 证券简称:保税科技 编号:临2025-029张家港保税科技(集团)股份有限...
强对流天气频繁组团来袭,该如何... 转自:上观新闻昨日,北京气象台发布了三个预警信息,雷电、冰雹和大风的天气,这已经是本周内发布的第二个...
浙江省围海建设集团股份有限公司... 证券代码:002586 证券简称:*ST围海 公告编号:2025-048浙江省围海建设集团股份有限公...
持续近2小时,俄乌在土耳其谈成... 转自:上观新闻俄罗斯和乌克兰代表团16日在土耳其伊斯坦布尔举行关于和平解决乌克兰危机的会谈,当天的双...
返乡创业正当时 “我们壮乡的花米饭是用植物天然色素染色,这种黄色糯米是用密蒙花煮的,蓝色是用蝶豆花,黑色是用枫树叶…...
青神发放首笔畜禽养殖设施增信贷... 本报讯(四川日报全媒体记者 底伊乐 眉山观察 曾永丽)“我们目前已发放400万元贷款,还有100万元...
大唐国际发电股份有限公司关于中... 证券代码:601991 证券简称:大唐发电 公告编号:2025-023大唐国际发电股份有限公司关于...
把“15分钟社区生活圈”评估提...   新华社北京5月16日电(记者 王立彬)为城市规划定期体检,查“症状”、消“病灶”,减轻或避免“城...
停车场车辆起火 美国佛罗里达州... 转自:央视央视记者获悉,当地时间5月16日,美国佛罗里达州杰克逊维尔国际机场当日因停车场车辆起火而关...
以军称已启动对加沙大规模攻势 以色列国防军当地时间16日发表声明称,以军已经启动对加沙地带的大规模攻势,即代号为“基甸战车”的军事...
转型,迎向市场新风口 转自:贵州日报 德江县融媒体中心 何佳有 黄明跃 邓雅珲三人一组,一人手提茶袋、两人提着采茶机,穿梭...
河南双汇投资发展股份有限公司关... 证券代码:000895 证券简称:双汇发展 公告编号:2025-18河南双汇投资发展股份有限公司关...
芯片新规:美国低估了中国,高估... 美国商务部日前发布公告,宣布加强对全球芯片出口管制的新规。新规以莫须有的罪名,声称在世界任何地方使用...