似乎减法正在触发某种问题,结果值是错误的.
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.
应该怎样做才能确保正确计算?
要控制浮点运算的精度,应使用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
如前所述,这是进行浮点运算的结果.
如前一张海报所示,当您进行数值计算时,请使用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
另一个例子:
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至少保证了这方面的一致行为.
我会修改上面的例子如下:
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中,数字始终以字符串开头.
每当你用双打进行计算时,都会发生这种情况.这段代码会给你877.85:
double answer = Math.round(dCommission*100000)/ 100000.0;