最近在项目中遇到精度计算问题,用Double类型的数据减去Double类型的数据,得出的结果在预期之外,经过一番思考与学习,最后找到解决问题的方案。
一、浮点数运算导致精度问题现象
代码如下:
Double num1 = 2.1;
Double num2 = 2.0;
System.out.println(num1 - num2);
用人类的口算可以知道,结果是0.1。可是用程序执行出来的结果却出乎意料,执行结果为0.10000000000000009。执行结果如下图所示:
二、分析精度问题现象
我们知道,计算机发展了如此长的一段时间,但它始终只能识别0和1(即二进制)。无论我们使用哪种编程语言,在哪种编译环境下工作,都要先把源代码翻译成二进制的机器码才能被计算机所识别。举个简单的例子,在源程序里面2.4是十进制的,但计算机不能直接识别,要先编译成二进制。那么问题来了,2.4的二进制并非是精确的2.4,反而是最为接近的二进制表示是2.39999999999999999999。原因在于浮点数由两部分组成:指数和尾数,这点如果知道怎么进行浮点数的二进制和十进制转换,应该不难理解。如果在这个转换过程中,浮点数参与了计算,那么在转换的过程中就会变得不可预知,并且变得不可逆。我们有理由相信,就是在这个过程中,发生了精度的丢失。而至于为什么有些浮点计算会得到准确的结果,应该也是碰巧那个计算二进制和十进制之间能够准确转换。而当输出单个浮点型数据时,可以正确输出,如:
Double num3 = 2.4;
System.out.println(num3);
输出的结果是2.4,而不是2.399999999999999999999999。也就是说,不进行浮点计算的时候,在十进制里浮点数能正确显示。这正印证了上面的说法,即入股浮点数参与了计算,那么浮点数二进制与十进制的转换过程就会变得不可预知,并且变得不可逆。
三、float、double数据类型
float和double浮点数的精度是由尾数的位数来决定的。浮点数在内存中是按科学计算法来存储的&#