关于期望由单独计算产生的两个浮点数完全相等的危险,已经有很多问题和答案,因为浮点数不是实数。这个问题不是关于基于相等性检查的正确性,而是关于基于它的缓存。
想象一下你有这样的代码:
if(myfloat != _last_float) {
refresh_expensive_computation(myfloat);
_last_float = myfloat;
}
在这种情况下,相等比较纯粹是为了防止做多余的工作。如果输入不变,我们将避免再次进行昂贵的计算(我们假设昂贵的函数是确定性的,并且它的其他输入没有改变)。
如果两者真的相等(这意味着如果我们可以用实数而不是浮点数计算它们就会相等)但被错误地检测到不相等,在最坏的情况下,我们会冗余地进行昂贵的计算,但我们的程序的答案仍然是正确的。AFAIK,如果计算是在比浮点数的内存表示更宽的寄存器中完成的(例如,在启用 80 位 fp 寄存器时在 32 位 x86 上),它们只能错误地比较相等,并且在转换为内存表示后它们会发生两者按位相等。在这种情况下,差异必须超出内存表示的精度,对于对我来说很重要的比较,它必须低于 epsilon,因为否则我会使用更广泛的类型,比如 double。
所以我要断言这种使用浮点相等是安全的。所以第一个问题是,我错了吗?
其次,如果我们假设它是安全的,我想避免错误地返回 true,因为它会导致昂贵的计算。在寄存器比内存表示更宽的机器上避免这种情况的一种方法是使用 memcmp 强制它比较内存表示(NaN 的语义不会完全相同,现在它将与完全相同的按位实例进行比较本身,但对于缓存这是一种改进,或者对于 +0 和 -0 但可能是特殊情况)。但是,该 memcmp 将比寄存器中的浮点比较慢。有没有办法检测平台何时具有更宽的寄存器,所以我可以 #ifdef 或类似的方法在安全的平台上获得优化的实现?