浮点计算中的近似处理问题
在浮点计算中经常会遇到这样的情景:检查一个数值是否为另一个数值的整数倍。这个问题对于整数计算而言完全不是问题,但放到浮点数身上就存在误差导致的近似问题。
比如两个浮点数相除:d1 / d2 = 2.9981,那么 d1 是否是 d2 的整数倍呢?这取决于允许的误差精度,如果误差精度为 0.01 那么 d1 就可以近似为 d2 的3倍;但如果误差精度为 0.001 那么 d1 就不是 d2 的整数倍。
下面提供一个函数实现来完成上面的整数倍计算。
//
// 检查一个浮点数是否为另一个浮点数的整数倍,如果结果是 true,则将整数倍数保存在 mult 指针中;
// 如果 multi 指针为 NULL 则不返回倍数
//
// 参数说明
// a 除数
// b 被除数
// prec 误差精度,比如:0.0001
// mult 指向保存整数倍数的变量,可以为 NULL,如果不是整数倍则不改变该指针指向变量的值
//
// 返回值
// a是否为b的整数倍
//
bool CheckDoubleMultiple(double a, double b, double prec, int *mult) {
// 先计算相除的结果
double d = a / b;
// 给原始相除的结果加上误差精度值,如果 d 可以近似为整数倍,那么 m 的值就是该整数倍数
double m = (double)((int)(d + prec));
// 要求相除结果在区间 [ m - 0.0001, m + 0.0001 ] 内,注意:m 是一个整数值!
if ((d - prec) <= m && m <= (d + prec)) {
if ( mult ) *mult = static_cast<int>(m);
return true;
} else {
return false;
}
}
// 检查一个浮点数是否为另一个浮点数的整数倍,如果结果是 true,则将整数倍数保存在 mult 指针中;
// 如果 multi 指针为 NULL 则不返回倍数
//
// 参数说明
// a 除数
// b 被除数
// prec 误差精度,比如:0.0001
// mult 指向保存整数倍数的变量,可以为 NULL,如果不是整数倍则不改变该指针指向变量的值
//
// 返回值
// a是否为b的整数倍
//
bool CheckDoubleMultiple(double a, double b, double prec, int *mult) {
// 先计算相除的结果
double d = a / b;
// 给原始相除的结果加上误差精度值,如果 d 可以近似为整数倍,那么 m 的值就是该整数倍数
double m = (double)((int)(d + prec));
// 要求相除结果在区间 [ m - 0.0001, m + 0.0001 ] 内,注意:m 是一个整数值!
if ((d - prec) <= m && m <= (d + prec)) {
if ( mult ) *mult = static_cast<int>(m);
return true;
} else {
return false;
}
}