Float、Double类型相加精度问题
1.double 类型
double类型相加精度问题
double为浮点类型的数据,占用64bit,计算时为二进制计算方法,计算时容易出现精度丢失问题。
2.float为浮点类型的数据,占用32bit,计算时为二进制计算方法,十进制转化为二进制计算完毕在转化为十进制时可能造成精度丢失。
float浮点型整形部分的长度为10,小数部分位数为16;如果最后一位小数为0则用1代替
例 0.021+0.022计算结果
javaScript:
function add(value1, value2) {
var r1, r2, m;
try {
r1 = value1.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = value2.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
var value= (value1 * m + value2 * m) / m;
return value;
}
function count(){
add(0.021,0.022)
}
java:
public static float subtract(float value1,float value2){
int r1, r2;
try {
r1 = Float.toString(value1).split(".")[1].length();
} catch (Exception e) {
r1 = 0;
}
try {
r2 = Float.toString(value2).split(".")[1].length();
} catch (Exception e) {
r2 = 0;
}
float m = (float)Math.pow(10, Math.max(r1, r2));
float value = (value1 * m - value2 * m) / m;
return value;
}
相加结果为:0.042999998
相减结果为:0.0010000002
float、double精度丢失原因:
float、double计算时都是先转化为二进制,然后计算,计算结果再转化为十进制
精度的丢失就出现在十进制转二进制,二进制再转十进制的过程中
举例说明
22 二进制:10110
21 二进制:10101
二进制相减为:1转为十进制为1;22-21=1没有问题。
0.022f 二进制:
0.000001011010000111001010110000001000001100010010011011101
0.021f 二进制:
0.0000010101100000010000011000100100110111010010111100011011
长度分别为60和61,但是float类型长度最大为32,会进行四舍五入,去除多余的二进制数,已处理的二进制相加减生成的新的二进制再转化为十进制肯定是有误差的,double同理
如何解决float和double进度丢失
使用BigDecimal计算
对超过16位有效的数进行精准的运算,计算精准
BigDecimal所创建的为对象,所以不能用"+、-、*、"等
相加:add(BigDecimal)
相减:substract(BigDecimal)
相乘:multiply(BigDecimal)
相除:divide(BigDecimal)
转为字符串:toString()
doubleValue():转为双精度数
floatValue():转为单精度数
longValue():转为长整数
intValue():转为整数
//相除结果四舍五入保留两位小数
被除数.divide(除数,2,BigDecimal.ROUND_HALF_UP);
BigDecimal.setScale() //格式化小数点
setScaler(1) //保留一位小数,默认为四舍五入
setScaler(1,BigDecimal.ROUND_UP) //进位处理,2.35变为2.4
setScaler(1,BigDecimal.ROUND_DOWN) //降位处理,2.35变为2.3
setScaler(1,BigDecimal.ROUND_HALF_DOWN) //五舍六入 ,2.35变为2.3,如果后一位为5则向下降位