关于float和double数据相加减出现结果和预期不一致的问题

前言: 我先写一段测试代码来说明一下问题

    @Test
    public void testCalculateScoreFloat(){
        int fanScore = 14, flowers = 9, result = 0;
        float bascScore = 500;
        float[] basicPoint = {0f, 0.05f, 0.5f, 1f, 2f, 3f, 5f};
        float[] flowerPoint = {0f, 0.05f, 0.5f, 1f, 2f, 3f, 5f};

        float flowerScore = flowerPoint[1] * (fanScore + flowers);
        float winScore = basicPoint[1] + flowerPoint[1] * (fanScore + flowers);

        result = (int) (bascScore * winScore);
        System.out.println("basicPoint[1]: " + basicPoint[1] + ", flowerScore: "+ flowerScore + ", winScore: " + winScore + ", result: " + result);
    }

输出结果为:basicPoint[1]: 0.05, flowerScore: 1.15, winScore: 1.1999999, result: 599
哎呀,你说奇怪不奇怪,0.05 + 1.15 = 1.2,没毛病啊,怎么突然变成了1.1999999。顿时我和我受过九年义务教育的小伙伴们吃了一惊。
原因: 我们都知道计算机是通过二进制进行运算的,首先需要把0.05和1.15转化为二进制然后再加起来:
十进制小数转化为二进制数算法是乘以2直到没有了小数为止。
0.15表示成二进制数:
0.15*2=0.3 取整数部分 0
0.3*2=0.6 取整数部分 0
0.6*2=1.2 取整数部分 1
0.2*2=0.4 取整数部分 0
0.4*2=0.8 取整数部分 0
0.8*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 1
………
0.15二进制表示为(从上往下): 0010010011……

0.05表示成二进制数:
0.05*2=0.1 取整数部分 0
0.1*2=0.2 取整数部分 0
0.2*2=0.4 取整数部分 0
0.4*2=0.8 取整数部分 0
0.8*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 1
0.2*2=0.4 取整数部分 0
………
0.05二进制表示为(从上往下): 00001100……
两个小数转为二进制时都出现了无限循环,就好像十进制中无法精确表示1/3一样,出现了精度的损失,所以0.05+1.15加起来的结果无限接近1.2,但是不等于1.2.

解决方法: 在java中,使用BigDecimal来处理

    @Test
    public void testBigDecimalFloat(){
        BigDecimal socre1 = new BigDecimal("1.15");
        BigDecimal socre2 = new BigDecimal("0.05");
        float result = socre1.add(socre2).floatValue();
        System.out.println("result: " + result);
    }

补充:这里我建议大家使用BigDecimal(String val),而不建议使用BigDecimal(double val)构造函数,因为后者仍存在精度损失。这两者的差别,相信大家会在存取数据库的时候遇到。

你可能感兴趣的:(工作中)