关于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);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

输出结果为: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.15二进制表示为(从上往下): 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);
    }

猜你喜欢

转载自blog.csdn.net/lang_niu/article/details/81004452