double精度丢失

double测试代码:

    @Test
    public void testDouble() {
        double d1 = 2.01d;
        double d2 = 2.0099999999999997868371792719699442386627197265625d;
        System.out.println("d1 == d2 : " + (d1 == d2));
        System.out.println("d1 * 100 = " + (d1 * 100));
        System.out.println("d2 * 100 = " + (d2 * 100));
    }

测试结果

d1 == d2 : true
d1 * 100 = 200.99999999999997
d2 * 100 = 200.99999999999997

说明以double类型保存在计算机里面的浮点数d1=2.01的真实值是d2的值,double类型无法精准表示2.01,声明赋值时,就已经丢失精度了

BigDecimal表示小数:准确的用法是以字符串形式,使用BigDecimal构造函数创建

    @Test
    public void testBigDecimal() {
        double d1 = 2.01d;
        String d1Str = "2.01";
        System.out.println(new BigDecimal(d1Str).toPlainString());
        //与上面以字符串为参数,用构造函数创建是等价的
        System.out.println(BigDecimal.valueOf(d1).toPlainString());
        //以double类型传入,会得到因double而丢失精度之后的值
        System.out.println(new BigDecimal(d1).toPlainString());
    }

结果:

2.01
2.01
2.0099999999999997868371792719699442386627197265625

这里之所以要以字符串为BigDecimal构造函数参数,是因为BigDecimal是精确的,如果直接传入double类型参数,会把double类型记录在计算机中的真实值(例如声明 double d1 = 2.01d;此处由于十进制的小数不能用有限长的二进制小数来表示而丢失精度,实际保存的真实值是2.0099999999999997868371792719699442386627197265625,与2.01近似而已,在声明double类型赋值时,精度就丢失了)传给BigDecimal,而我们真正想要的值就是我们看到的值2.01,所以应该直接传入字符串"2.01"。

其他测试

    @Test
    public void testEquals() {
        double d1 = 2.01d;
        double d2 = 2.0099999999999997868371792719699442386627197265625d;
        System.out.println(d1 == d2);
        System.out.println(Double.toString(d1));
        System.out.println(Double.toString(d2));
        System.out.println(new BigDecimal(d1).equals(BigDecimal.valueOf(d1)));
        System.out.println(new BigDecimal(d2).equals(BigDecimal.valueOf(d2)));
        System.out.println(new BigDecimal(d1).equals(new BigDecimal(d2)));
        System.out.println(BigDecimal.valueOf(d1).equals(BigDecimal.valueOf(d2)));
    }

测试结果:

true
2.01
2.01
false
false
true
true

double丢失精度原因:
N 位二进制的小数的精度是 1/2 的 N 次方。也就是说,N 位二进制数只能表示(1/2 的 N 次方)的整数倍的数。M 位十进制的小数的精度是 1/10 的 M 次方。1/10 = 1/2 * 1/5。那么 1/5 这个数(即0.2),就不能用有限长的二进制小数来表示。
参考:
Double和Float运算以及DecimalFormat格式化精度丢失踩坑记录
https://blog.csdn.net/xdkb159/article/details/106081425

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值