浮点数相等

(2 mins to read)

IEEE浮点标准

V=(-1)^S\times M\times 2^E

  • S是符号位
  • E是阶码,对浮点数加权
  • M是尾数,即二进制小数

float: 1位s,8位exp,23位frac

double:1位s,11位exp,52位frac

规格化值

exp不为全0,也不为全1。

$E = exp - Bias$,其中对于8位的exp,Bias为127,而对于11位的exp,Bias为1023。

$M = 1 + f$

FLT_EPSILONDBL_EPSILON被定义为浮点表示中1.0的下一个,即最小的正整数$x$,满足$1.0 + x != 1.0$。

显然,当一个浮点数的数值越大,那么可用于表示小数的位数就越少,相邻的可表示浮点数间的间距也就越大。

浮点数相等判断

1
2
3
4
5
6
7
8
9
10
11
bool absoluteToleranceCompare(double x, double y) {
return std::fabs(x - y) <= std::numeric_limits<double>::epsilon() ;
}
bool relativeToleranceCompare(double x, double y) {
double maxXY = std::max( std::fabs(x) , std::fabs(y) ) ;
return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXY ;
}
bool combinedToleranceCompare(double x, double y) {
double maxXYOne = std::max( { 1.0, std::fabs(x) , std::fabs(y) } ) ;
return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXYOne ;
}

使用绝对容忍对于小于等于1.0的数值是可行的,但是对于大于1.0的数值过于严格。使用相对容忍则对于小于1.0的数值过于容忍。

因此最好的方式是结合这两者。