float,double类型用BigDecimal.ROUND_HALF_UP 四舍五入失败简析

今天程序出了一个BUG,偶尔会出现订单与实际差了一分钱的情况。

因为我们的数额是精确到小数点后三位,但订单只需要两位,于是我就对BigDecimal做了个测试。

 public static void main(String[] args) {
        float elect = 3.155f;
        System.out.println(new BigDecimal(elect).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
    }

输出结果理想情况应该为 3.16,可实际情况是


不科学,又试验了多次,

 public static void main(String[] args) {
        float elect = 3.105f;
        for (int i = 0; i < 10; i++) {
            System.out.println("elect:"+elect+"---------format:"+new BigDecimal(elect).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
            elect = elect + 0.01f;
        }

    }
elect:3.105---------format:3.11
elect:3.115---------format:3.12
elect:3.125---------format:3.13
elect:3.135---------format:3.13
elect:3.145---------format:3.14
elect:3.155---------format:3.15
elect:3.165---------format:3.16
elect:3.175---------format:3.17
elect:3.185---------format:3.18
elect:3.195---------format:3.19
都没生效,换个类型试一下,用double

  public static void main(String[] args) {
        double elect = 3.105d;
        for (int i = 0; i < 10; i++) {
            System.out.println("elect:"+elect+"---------format:"+new BigDecimal(elect).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
            elect = elect + 0.01d;
        }

结果不尽人意
elect:3.105---------format:3.10
elect:3.1149999999999998---------format:3.11
elect:3.1249999999999996---------format:3.12
elect:3.1349999999999993---------format:3.13
elect:3.144999999999999---------format:3.14
elect:3.154999999999999---------format:3.15
elect:3.1649999999999987---------format:3.16
elect:3.1749999999999985---------format:3.17
elect:3.1849999999999983---------format:3.18
elect:3.194999999999998---------format:3.19
Java中的简单浮点数类型float和double不能够进行运算,会因为进制转换

而导致精准度错误,这个不在这次讨论范围。

改一下程序:

  public static void main(String[] args) {
        List<Double> ele=new ArrayList<>();
        ele.add(3.105d);
        ele.add(3.115d);
        ele.add(3.125d);
        ele.add(3.135d);
        ele.add(3.145d);
        ele.add(3.155d);
        ele.add(3.165d);
        ele.add(3.175d);
        ele.add(3.185d);
        ele.add(3.195d);
        double elect = 3.105d;
        for (int i = 0,length=ele.size(); i < length; i++) {
            System.out.println("elect:"+ele.get(i)+"---------format:"+new BigDecimal(ele.get(i)).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        }

    }
输出结果依然很奇怪:

elect:3.105---------format:3.10
elect:3.115---------format:3.12
elect:3.125---------format:3.13
elect:3.135---------format:3.13
elect:3.145---------format:3.15
elect:3.155---------format:3.15
elect:3.165---------format:3.17
elect:3.175---------format:3.17
elect:3.185---------format:3.19
elect:3.195---------format:3.19
可见部分成功,部分失败,也就是说double依然是不可以

用String试一下

  public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            String elect = "3.1"+i+5;
            System.out.println("elect:" + elect + "---------format:" + new BigDecimal(elect).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        }
    }
结果可喜:

elect:3.105---------format:3.11
elect:3.115---------format:3.12
elect:3.125---------format:3.13
elect:3.135---------format:3.14
elect:3.145---------format:3.15
elect:3.155---------format:3.16
elect:3.165---------format:3.17
elect:3.175---------format:3.18
elect:3.185---------format:3.19
elect:3.195---------format:3.20

全部正确。

在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal。

所以我们需要金额或者相关数据精准度计算是一定要用String类型来计算

回到最初的程序,float计算,转成String

public static void main(String[] args) {
        float elect = 3.155f;
        System.out.println(new BigDecimal(String.valueOf(elect)).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
    }
结果就是正确的了

3.16

OVER。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值