Java中BigDecimal对象与double之间转换涉及的精度问题及“no exact representable decimal result.”解决方案

当我们在开发的时候,有时候根据需求来讲,会要求小数点后精确到几位数,例如涉及到费用的问题,通常会让我们精确到小数点后4位,就类似于“0.3333”的格式,当我们在想要进行精确到小数点后几位时,这时候就会想到BigDeimal对象来进行转化,不过在进行转化的过程中,笔者遇见了几个不小的“坑”。

1.BigDecimal的构造方法

我们来看看JDK1.8中对BigDecimal对象是如何解释他的构造方法的吧。

我们今天主要说一下BigDecimal对象中构造方法传入double与String的区别。我们来通过一些代码来看一下两者的实际效果

1)BigDecimal(double val) 

当我们想要保留小数点后四位小数,构造方法为double时,会出现什么情况呢?

     当我们直接定义一个double数据a,通过BigDecimal对象进行转换时,发现并没有精度的损失,

但是,当我们设置另外一个double数据b时,两个double数据做除运算,我们来看一看发生了什么

我们会发现,当我们直接打印出 a / b 时,此时未做转换,c 为 0.85;但是当我们把 a / b 的结果放入构造方法中时(即把0.85放入构造方法中),会发现,最后通过BigDecimal对象转化出的double数据为0.8499;

所以我们可以得出一个结论,当BigDecimal构造方法对象为double时,会出现精度的损失。

这时候可能会有人说,你构造方法中传入的是 “a / b”,那是否是a/b运算出现的精度损失,而并非是构造方法中直接传入的double出现的精度损失?

首先,第一点,double型数据做运算得出的结果同样也是double型数据,第二点,我们来看看系统的运算结果:

所以,综上我们可以得出一个结论,即:当BigDecimal构造方法对象为double时,会出现精度的损失。

 

彩蛋:我们没限制BigDecimal的位数的时候,它的值是多少呢?

这时候我不得不怀疑,double本身可能就是个有问题的数据呀【滑稽】

 

2)BigDecimal(String val)

我们同样做一个实验,把步骤1中传入的double数据改为String类型时,会发现这样一个有趣的现象。

很神奇,当传入的是String时,并未出现精度的损失,amazing

所以!我大胆瞎猜!double是基本数据类型!有位数限制!可能内部早就做了四舍五入的处理!String没有位数限制!所以没有精度损失![这句话我瞎说的]

 

还有一个地方需要大家注意,当在做double数据除运算的时候,中间转为String可以,但是还有一个方法,就是把doule都转为BigDecimal对象,然后再做除运算;

 

注意圈出的部分,如果不设置这一步,并且是有无限循环时,就会报错:

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 TestProject.main(TestProject.java:18)

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在进行浮点数运算或者使用BigDecimal进行除法运算时,有些数无法被精确表示,因为它们的十进制小数位是无限循环的,例如1/3,0.1等。在这种情况下,运算结果也无法被精确表示,因为它们的十进制小数位也是无限循环的。 在Java,如果进行了这种运算,抛出`ArithmeticException`异常,异常信息为"Non-terminating decimal expansion; no exact representable decimal result.",表示运算结果无法被精确表示为一个有限小数。 例如,下面的代码抛出该异常: ```java import java.math.BigDecimal; public class Main { public static void main(String[] args) { BigDecimal dividend = new BigDecimal("1"); BigDecimal divisor = new BigDecimal("3"); BigDecimal result = dividend.divide(divisor); System.out.println(result); } } ``` 输出结果为: ``` Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. at java.math.BigDecimal.divide(BigDecimal.java:1697) at Main.main(Main.java:6) ``` 要解决这个问题,可以使用`setScale()`方法将结果舍入到指定的小数位数,例如: ```java import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public static void main(String[] args) { BigDecimal dividend = new BigDecimal("1"); BigDecimal divisor = new BigDecimal("3"); BigDecimal result = dividend.divide(divisor, 3, RoundingMode.HALF_UP); System.out.println(result); } } ``` 输出结果为: ``` 0.333 ``` 在这个例子,我们使用`setScale()`方法将结果舍入到小数点后3位,并使用`RoundingMode.HALF_UP`模式进行舍入,得到了一个近似值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值