将 float 宏与 int* 一起切换 - 它有什么作用?

Toggle float macro together with int* - What does it do?

我试图了解 OpenCV 中的 AKAZE 功能实现,当我遇到以下宏时感到困惑:

/* IEEE754 constants and macros */
#define  CV_TOGGLE_FLT(x) ((x)^((int)(x) < 0 ? 0x7fffffff : 0))

它在 MLDB 二进制比较中的使用方式如下(我删除了所有不相关的代码部分):

void MLDB_Binary_Comparisons(float* values)
{
    int* ivalues = (int*)values;
    for (int i = 0; i < count * chan; i++)
        ivalues[i] = CV_TOGGLE_FLT(ivalues[i]);

    /* ... The ivalues are then compared to each other using the > operator */
}

有人知道这里发生了什么吗?将 float* 转换为 int* 真的安全吗,这个宏到底是做什么的?

提前致谢!

本质上,它以不可移植的方式对浮点数据进行一些二进制操作:对于 intfloat 的相对大小以及关于他们的代表。我认为 if int 是一个 32 位的 2 的补码整数,而 float 是一个 IEEE 32 位浮点值,那么它可以让你比较仅使用整数运算的浮点值。

更详细...

int* ivalues = (int*)values;

这只是给了我们一个用于遍历浮点值的指针。它们被解释ints,而不是转换int——换句话说,没有理由认为值为 1.0float 将映射到 1int 值。因此,您可以做的主要事情是按位运算,或依赖于理解用于 float 的二进制格式的特定操作。

看微距...

#define  CV_TOGGLE_FLT(x) ((x)^((int)(x) < 0 ? 0x7fffffff : 0))

x(记住,只是一些表示浮点值的位,但这里我们只是将其视为位模式)与 0(无效)或 0x7fffffff(反转低位 31 位)。做什么的决定取决于 x 是否小于零。

我认为这个宏是基于这样的假设:int 是一个 32 位的 2 的补码表示。这意味着如果设置了最高位,则 x < 0 为真。与 0x7fffffff 的 XOR 将反转其他位。这将意味着 -1,最正的负数,从 0xffffffff 变为 0x8000000,这是最负的负数(-2147483648),同样 [=32] =] 变成 0xffffffff。当您在此之后使用 > 来比较两个负数时,这意味着 更负的 数字现在是 更正的 number,然后将采用 "greater than" 分支。比较两个正数是不变的,并且将正数与负数进行比较,如您所料,正数仍然总是更大。

这使您可以仅使用整数运算对 float 进行比较。这是因为 floats 在 IEEE 格式中存储负数的方式与 2 的补码有很大不同:符号位实际上只是一个标志,表示值是正数还是负数,其余位存储大小的数量。应用 CV_TOGGLE_FLT(x) 后,您没有可以直接使用的值,但它们的排序方式与原始 float 值相同。