java - BigDecimal 除法为某些计算返回错误的结果
问题描述
我已经阅读了一些关于浮点数及其数学的问题。对我来说,这些问题似乎只发生在更大的范围内(即 10+ 小数)。现在我的问题已经发生在小数点后 2 位,并且在某些情况下非常严重:
以下代码:
System.out.println(
String.format("%.2f", BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()));
System.out.println(
String.format("%.2f", BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2).doubleValue()));
分别生成此输出:
0.80
0.89
如果我手动执行计算(使用谷歌计算),我会得到以下结果:
0.72351421188
0.88278388278
对于第一次计算,结果非常大(约 0.08 折),而对于第二次计算,结果非常低(约 0.01 折)。
关于为什么第一个结果如此之大,是否有一些理智的解释?或任何方法来获得正确的结果使用BigDecimal
?
注意
System.out.println(2.8/3.87);
实际上返回正确的结果(0.7235142118863048)。
另请注意,这些String.format
东西仅用于检查结果是否被它更改,事实并非如此。BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()
产生完全相同的结果。
解决方案
问题是您使用了错误BigDecimal#divide
的四舍五入到小数点后两位。以下是这些BigDecimal#divide
方法的可用参数:
divide(BigDecimal divisor)
divide(BigDecimal divisor, int roundingMode)
divide(BigDecimal divisor, MathContext mc)
divide(BigDecimal divisor, RoundingMode roundingMode)
divide(BigDecimal divisor, int scale, int roundingMode)
divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
由于您使用divide
带有 aBigDecimal
和int
参数的 a,因此它使用divide(BigDecimal divisor, int roundingMode)
,其中您2
是舍入模式而不是比例。在这种情况下,2
实际上是ROUND_CEILING
,并且未指定比例。
相反,您必须使用divide(BigDecimal divisor, int scale, int roundingMode)
或divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
。因此,将您的电话更改为:
System.out.println(BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2,
BigDecimal.ROUND_HALF_UP));
System.out.println(BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2,
BigDecimal.ROUND_HALF_UP));
(随意使用除 之外的舍入模式ROUND_HALF_UP
。)
我不确定默认情况下它使用什么比例,但是ROUND_CEILING
您指定的比例2
导致了计算中的问题。
至于提到的评论,有三种可能的方法来创建BigDecimal
具有指定值的:
BigDecimal.valueOf(2.8)
new BigDecimal(2.8)
new BigDecimal("2.8")
仍然会new BigDecimal(2.8)
给出浮点错误,所以我建议您使用BigDecimal.valueOf(2.8)
您已经做过的或者 String 构造函数new BigDecimal("2.8")
。
然而,这与您的舍入问题有点无关,因为无论您使用了何种初始化,使用正确的divide
方法都会给出正确的结果:BigDecimal
推荐阅读
- r - 为变量输入泛化 R 函数
- android - 如何更改 Intent.ACTION_EDIT 的目标活动
- html - 使用蒙版在 div 上自定义底部边框
- python - SSH 上的 Selenium Chrome 浏览器
- sql - 当产品出现在临时表中时,根据临时所有类型的订单的记录更新语句主表
- python - kivy-按下 MDFloatingActionButtonSpeedDial 后如何添加功能
- python - Cloud Pub/Sub 订阅者 max_messages 不适用于消息排序
- r - R中的绘图点在错误的位置?
- python - 如何使用 python 请求和 BeautifulSoup 在网站上的 html 中查找隐藏值
- hl7-v2 - HL7 附加段