我已经阅读了一些有关浮点数及其数学的问题。对我来说,问题似乎只在更大的范围内发生(即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
如果我手动执行计算(使用Google计算),则会得到以下结果:
0.72351421188
0.88278388278
对于第一个计算,结果确实很大(〜0.08 off),而对于第二个计算,结果非常低(〜0.01 off)。
关于第一个结果为何如此之大,是否有一些理智的解释?还是通过BigDecimal
获得正确结果的任何方法?
请注意
System.out.println(2.8/3.87);
实际上返回正确的结果(0.7235142118863048)。
还请注意,String.format
内容仅用于检查结果是否被更改(事实并非如此)。 BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()
产生完全相同的结果。
答案 0 :(得分:6)
问题是您使用错误的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
和BigDecimal
参数的int
,因此它将使用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
初始化无关: