再把你的钱加倍

总览

很久以前,我写了一篇关于用双倍赚钱的文章。 但是,当解决方案相当简单时,仍然是许多开发人员普遍担心的问题。

用双倍赚钱的问题

double有两种类型的错误。 它存在表示错误。 即,它不能完全代表所有可能的十进制值。 即使0.1也不完全是这个值。 根据计算也有舍入误差。 即,当您执行计算时,误差会增加。

double[] ds = {
        0.1,
        0.2,
        -0.3,
        0.1 + 0.2 - 0.3};

for (double d : ds) {
    System.out.println(d + " => " + new BigDecimal(d));
}

版画

0.1 => 0.1000000000000000055511151231257827021181583404541015625
0.2 => 0.200000000000000011102230246251565404236316680908203125
-0.3 => -0.299999999999999988897769753748434595763683319091796875
5.551115123125783E-17 => 5.5511151231257827021181583404541015625E-17

您可以看到0.1和0.2的表示形式略高于这些值,-0.3的表示形式也略高。 当您打印它们时,您得到的更好的是0.1,而不是代表的实际值0.1000000000000000055511151231257827021181583404541015625

但是,将这些值加在一起时,会得到一个略高于0的值。

要记住的重要一点是这些错误不是随机错误。 它们是可管理的且受限制的。

修正舍入误差

像许多数据类型(例如日期)一样,您具有值的内部表示形式以及如何将其表示为字符串。

对于double来说是这样。 您需要控制如何将值表示为字符串。 由于Java对表示错误进行少量舍入并不明显,所以这可能会令人惊讶,但是,一旦对操作也产生舍入错误,就会有些震惊。

一个常见的反应是假设,您对此无能为力,该错误是无法控制,不可知且危险的。 放弃双倍并使用BigDecimal

但是,该错误在IEE-754标准中受到限制,并且累积缓慢。

舍入结果

就像需要使用TimeZone和Local作为日期一样,您需要在转换为String之前确定结果的精度。

要解决此问题,您需要提供适当的舍入。 有了钱,这很容易,因为您知道合适的小数位数,除非您有70万亿美元,否则舍入误差不会大到无法校正的程度。

// uses round half up, or bankers' rounding

public static double roundToTwoPlaces(double d) {
    return Math.round(d * 100) / 100.0;
}

// OR

public static double roundToTwoPlaces(double d) {
    return ((long) (d < 0 ? d * 100 - 0.5 : d * 100 + 0.5)) / 100.0;
}

如果将其添加到结果中,仍然会出现一个很小的表示错误,但是Double.toString(d)无法对其进行校正,不足以表示该错误。

double[] ds = {
        0.1,
        0.2,
        -0.3,
        0.1 + 0.2 - 0.3};

for (double d : ds) {
    System.out.println(d + " to two places " + roundToTwoPlaces(d) + " => " + new BigDecimal(roundToTwoPlaces(d)));
}

版画

0.1 to two places 0.1 => 0.1000000000000000055511151231257827021181583404541015625
0.2 to two places 0.2 => 0.200000000000000011102230246251565404236316680908203125
-0.3 to two places -0.3 => -0.299999999999999988897769753748434595763683319091796875
5.551115123125783E-17 to two places 0.0 => 0

结论

如果您有一个项目标准说应该使用BigDecimal或double,则应遵循该标准。 但是,没有充分的技术理由担心会花双倍的钱。

参考:Vanilla Java上 ,我们的JCG合作伙伴 Peter Lawrey 再次增加您的资金

相关文章:

翻译自: https://www.javacodegeeks.com/2011/08/double-your-money-again.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值