问题代码
float a = 0.f;
for(int i = 0; i < 10000; ++i){
a += 0.01f;
}
输出a的值结果为:
可以看到结果存在0.002953的误差,这是因为float的精度问题,在多次运算绝对误差不断累加所导致的。
解决方法
方法一:分段累加
float a=0.f;
for(int i = 0; i < 100; ++i){
float b = 0.f;
for(int j = 0; j < 100; j++){
b += 0.01f;
}
a += b;
}
采用这种方法输出a的值结果为99.999985,存在的误差为0.000015,比之前小了很多。减小相加两个浮点数之间的大小差距可以在一定程度上减少相加导致的误差。
方法二:贮存残留值
float a = 0.f;
float r = 0.f; //类积未加上的值
float t;
for(int i = 0; i < 10000; ++i){
r += 0.01f;
t = a; //保存本次加法前的a值
a += r; //执行本次加法
t = a - t; //本次加法中a实际增加的值
r = r - t; //理想a应增加的值 - 实际a增加的值 = 本次未加上的值
}
这个技巧初见比较不好理解,所以笔者基本每行代码都加了注释,用这个方法计算得到的a的值正正好为100,误差为0。
这个方法的核心就是用r记录每次加法后残留的没能加上的值,残留值在r中不断积累,最终在某次加法中成功加上。