c++ - 用于缓存昂贵计算的浮点相等

标签 c++ c floating-point floating-point-comparison

已经有很多关于期望由单独计算产生的两个 float 完全相等的危险的问题和答案,因为 float 不是实数。这个问题不是关于相等性检查的正确性,而是关于基于它的缓存。

假设您有以下代码:

if(myfloat != _last_float) {
    refresh_expensive_computation(myfloat);
    _last_float = myfloat;
}

在这种情况下,相等比较纯粹是为了防止做多余的工作。如果其输入不变,我们将避免再次进行昂贵的计算(我们假设昂贵的函数是确定性的,并且它的其他输入没有改变)。

如果两者确实相等(意味着如果我们可以使用实数而不是浮点进行计算,它们就会相等)但被错误地检测到不相等,在最坏的情况下,我们会冗余地进行昂贵的计算,但我们的程序的答案是仍然正确。据我所知,如果计算是在比 float 的内存表示更宽的寄存器中完成的(例如,在 32 位 x86 上,当启用 80 位 fp 寄存器时),并且在转换为内存表示之后,它们就会错误地比较相等两者按位相等。在这种情况下,差异必须超出内存表示的精度,对于对我来说重要的比较,该精度必须低于 epsilon,否则我将使用更宽的类型,例如 double。

所以我要断言浮点相等的使用是安全的。所以第一个问题是,我错了吗?

其次,如果我们假设它是安全的,我想避免错误地返回 true,因为它会导致昂贵的计算。在寄存器比内存表示更宽的机器上避免这种情况的一种方法是使用 memcmp 强制它比较内存表示(NaN 的语义不会完全相同,它现在将与完全相同的按位实例进行比较 true本身,但对于缓存来说这是一个改进,或者对于 +0 和 -0 但可能是特殊情况)。然而,memcmp 会比寄存器中的浮点比较慢。有没有办法检测平台何时具有更宽的寄存器,以便我可以 #ifdef 或类似的方法在安全的平台上获得优化的实现?

最佳答案

大多数memcmp实现对寄存器进行了小值优化,因此使用它应该没问题。但是,如果您不想依赖它,您也可以执行类似 reinterpret_cast<int>() 的操作。 。添加compile_assert(sizeof(int) == sizeof(float))如果您想更加安全并且正在使用包含此类命令的库集。

请注意 NaN。 NaN 不等于任何东西,甚至不等于另一个 NaN。如果您像这样比较内存,它们将显示为相等,这听起来就是您想要的,但是您可能需要添加额外的代码以确保所有 NaN 都被相同地对待。

关于c++ - 用于缓存昂贵计算的浮点相等,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39884432/

相关文章:

c - 如何使用 float.h 宏来提高浮点精度

c++ - 这是使用浮点值进行输入验证的正确方法吗?

c++ - 如果我将类声明为 const...而不是 constexpr,程序将无法运行?

c++ - 为什么隐式转换为 std::string 不适用于调用 operator<<

c++ - 读取浮点值时出错

c - 在 C 程序中接收 snmptraps

c++ - 使用两个链表

c++ - Cppcheck无法识别命令

c - 理解涉及进程的 C 代码

c - gcc 中的 printf 错误结果