Java开发之道
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

陷阱2 差值损失——浮点数相减造成的损失

对于浮点数相减,有时结果是正确的,有时结果是不正确的,所以在使用浮点数进行相减运算时,一定要注意应用的领域,特别是对于一些精密仪器的计算、导弹运行轨迹的运算以及航空母舰的运行轨迹,等等,一定要保证结果的正确性,稍有差异可能就会造成很大偏差或脱离轨道,由此造成的损失将是巨大的。

接下来通过两个示例来说明浮点数相减的结果有时是正确的,而有时是不正确的。

(1)计算结果正确的示例

示例:

    double result = 1.00 - 0.10 ;                // 将两个浮点数的差赋值给变量result
    System. out. println (result) ;               // 输出差值,也就是变量result的值

说明

上面示例输出result的值是0.9,这种情况属于正常的结果,因为确实1.00减去0.10的差应该是0.9。

(2)计算结果不正确的示例

示例:

    double result = 3.00 - 2.60 ;                // 将两个浮点数的差赋值给变量result
    System. out. println (result) ;               // 输出差值,也就是变量result的值

说明

上面示例输出result 的值是0.3999999999999999,这种情况属于不正确的结果,因为3.00减去2.60的正确差值应该是0.4。

由于浮点数相减结果错误,很有可能会造成不可估量的损失,尤其是对于一些精密的计算,因此必须要对浮点数相减运算进行处理,使其能计算出正确的结果。

下面是能够保证浮点数相减计算结果正确的两种方法。

(1)使用BigDecimal类

使用BigDecimal类对浮点数进行封装,然后通过该类的subtract ()方法计算两个数的差,这样就可以保证计算结果的正确性,但是前提是一定要用String 类型形参的构造方法,而不要用其他类型形参的构造方法创建BigDecimal对象,否则也会出现结果不正确的现象。

示例:

    BigDecimal num1 = new BigDecimal ("3.00") ; // 使用字符串创建BigDecimal对象num1
    BigDecimal num2 = new BigDecimal ("2.60") ; // 使用字符串创建BigDecimal对象num2
    BigDecimal num3 = num1. subtract (num2) ;     // 计算BigDecimal对象num1与num2的差
    double value = num3. doubleValue () ;           // 将差值num3转换为double型赋值给变量value
    System. out. println (value) ;                   // 输出差值,即输出value的值

说明

上面示例输出value的值是0.4,这是正确的结果,从而解决了浮点数相减错误的问题,但是这种做法可能会造成程序运行速度的下降,因为该类并没有很好地得到Java语言的支持。

(2)转换为整数

由于BigDecimal类没有很好地得到Java语言的支持,因此可以使用另一种方法来解决浮点数相减的问题,那就是将原来的数转换为整数,例如,将3.00和2.60各乘以100,并将结果强制转换为int型或long型,然后对整数做减法运算,并将运算结果转换为浮点数,方法是用差值除以100.0,从而得到最终的结果,这种做法程序的运行速度较快。

示例:

    double dbNum1 = 3.00 ;                   // 定义double型变量dbNum1,其值是3.00
    double dbNum2 = 2.60 ;                   // 定义double型变量dbNum2,其值是2.60
    long lngNum1 = (long) (dbNum1 * 100) ; // 将dbNum1的值乘以100后,转换为long型
    long lngNum2 = (long) (dbNum2 * 100) ; // 将dbNum2的值乘以100后,转换为long型
    long lngResult = lngNum1 - lngNum2 ;     // 计算两个long型值的差并赋值给变量lngResult
    double dbResult = lngResult / 100.0 ;    // 用long型差值除以100.0,即转换为double型
    System. out. println (dbResult) ;         // 输出最终结果

说明

上面示例输出dbResult的值是0.4,这是正确的结果,从而解决了浮点数相减错误的问题,并且这种做法速度更快,因此,对于频繁的浮点数相减运算就应尽量采用这种方法来实现,当然计算频率较少时,可以使用BigDecimal类来实现。

编程准则:尽量将浮点数相减转换为整数相减

在进行浮点数相减运算时,除非对精度要求不高,否则应该将浮点数转换为整数,然后再对转换后的整数进行相减运算,最后再对计算结果进行处理,将其转换为浮点数,这样就可以得到精确的结果。