Java中double或float运算丢失精度问题
计算机内部是用的是二进制码,当输入float或者double类型的十进制数进行运算的时候,会先转化成二进制数再进行运算,最后在转化为十进制输出。然而有些数字不能完全转化成二进制,计算机只能将结果无限趋近于原本十进制的数值,故会出现精度丢失的问题。
举例:
public static void main(String[] args) {
double a = 0.05;
double b = 0.07;
double c = a+b;
System.out.println(c);
float x = 0.05f;
float y = 0.07f;
float z = x+y;
System.out.println(z);
}
输出:
进制转化分为整数部分和小数部分,对于整数部分相信很多人都很清楚,小数部分则稍微麻烦一些,java中只提供了整数的进制转化代码。下面的链接和二维码是一篇关于二进制、八进制、十进制、十六进制之间转换的博客,比较详细。
https:二进制、八进制、十进制、十六进制之间的转换
十进制转换为二进制小数部分采用“乘二取整”,十进制0.05转换为二进制为0.00001100110011001100110011001100110011001100110011001101(保留56位小数);
十进制0.07转换为二进制为0.00010001111010111000010100011110101110000101000111101100(保留56位小数);
再将二进制相加,计算时先把两个二进制数对齐(以小数点对齐),1+1=10,此时向上一位进1,0写在本位,计算方式如下图所示:
结果为0.00011110101110000101000111101011100001010001111010111001。
最后将二进制转换为十进制得到0.12000000000000001,看似简单,实则暗藏玄机啊。
对于double或float计算可以采用BigDecimal类,如下:
public static void main(String[] args) {
double a = 0.05;
double b = 0.07;
double c = Double.valueOf(BigDecimal.valueOf(a).add(BigDecimal.valueOf(b)).toString());
System.out.println(c);
float x = 0.05f;
float y = 0.07f;
float z = Float.valueOf(BigDecimal.valueOf(x).add(BigDecimal.valueOf(y)).toString());
System.out.println(z);
}