当前位置:  开发笔记 > 编程语言 > 正文

如何解决Java Rounding Double问题

如何解决《如何解决JavaRoundingDouble问题》经验,为你挑选了5个好方法。

似乎减法正在触发某种问题,结果值是错误的.

double tempCommission = targetPremium.doubleValue()*rate.doubleValue()/100d;

78.75 = 787.5*10.0/100d

double netToCompany = targetPremium.doubleValue() - tempCommission;

708.75 = 787.5 - 78.75

double dCommission = request.getPremium().doubleValue() - netToCompany;

877.8499999999999 = 1586.6 - 708.75

由此产生的预期值为877.85.

应该怎样做才能确保正确计算?



1> Eric Weilnau..:

要控制浮点运算的精度,应使用java.math.BigDecimal.阅读John Zukowski对BigDecimal的需求以获取更多信息.

举个例子,最后一行如下使用BigDecimal.

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf("1586.6");
BigDecimal netToCompany = BigDecimal.valueOf("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

这导致以下输出.

877.85 = 1586.6 - 708.75


你无法完全"避免"浮点算术错误.表示数字时使用的位数总是有限的.您所能做的就是使用具有更高精度(位)的数据类型.
我将添加一个注释,BigDecimal _division_需要与+, - ,*略有不同,因为默认情况下,如果它不能返回精确值(例如1/3),它将抛出异常.在我使用过的类似情况中:BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b),25,RoundingMode.HALF_UP).doubleValue(),其中25表示精度的最大数字(超过double结果所需的数字) ).

2> Johann Zacha..:

如前所述,这是进行浮点运算的结果.

如前一张海报所示,当您进行数值计算时,请使用java.math.BigDecimal.

但是,有一个问题需要使用BigDecimal.当您从double值转换为a时BigDecimal,您可以选择使用新BigDecimal(double)构造函数或BigDecimal.valueOf(double)静态工厂方法.使用静态工厂方法.

双重构造的整个精度转换double到一个BigDecimal,而静态工厂有效地将其转换为一个String,然后将其转换是一个BigDecimal.

当您遇到那些微妙的舍入错误时,这就变得相关了.数字可能显示为.585,但在内部其值为"0.58499999999999996447286321199499070644378662109375".如果你使用了BigDecimal构造函数,你会得到不等于0.585的数字,而静态方法会给你一个等于0.585的值.

double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));

在我的系统给出

0.58499999999999996447286321199499070644378662109375
0.585


我多次遇到这个问题,真的很烦人!
注意,原因是静态方法使用UNLIMITED MathContext实际意味着:new BigDecimal(value,new MathContext(0,RoundingMode.HALF_UP));)

3> toolkit..:

另一个例子:

double d = 0;
for (int i = 1; i <= 10; i++) {
    d += 0.1;
}
System.out.println(d);    // prints 0.9999999999999999 not 1.0

请改用BigDecimal.

编辑:

此外,只是指出这不是一个'Java'舍入问题.其他语言表现出类似(但不一定一致)的行为.Java至少保证了这方面的一致行为.



4> 小智..:

我会修改上面的例子如下:

import java.math.BigDecimal;

BigDecimal premium = new BigDecimal("1586.6");
BigDecimal netToCompany = new BigDecimal("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

这样就可以避免使用字符串开头的陷阱.另一种选择:

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf(158660, 2);
BigDecimal netToCompany = BigDecimal.valueOf(70875, 2);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

我认为这些选项比使用双打更好.在webapps中,数字始终以字符串开头.



5> Steve Klabni..:

每当你用双打进行计算时,都会发生这种情况.这段代码会给你877.85:

double answer = Math.round(dCommission*100000)/ 100000.0;


最好用100000.0除而不是100000;Math.round返回long,因此您将使用整数除法。
推荐阅读
虎仔球妈_459
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有