将 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* 真的安全吗,这个宏到底是做什么的?
提前致谢!
本质上,它以不可移植的方式对浮点数据进行一些二进制操作:对于 int
和 float
的相对大小以及关于他们的代表。我认为 if int
是一个 32 位的 2 的补码整数,而 float
是一个 IEEE 32 位浮点值,那么它可以让你比较仅使用整数运算的浮点值。
更详细...
int* ivalues = (int*)values;
这只是给了我们一个用于遍历浮点值的指针。它们被解释为ints
,而不是转换为int
——换句话说,没有理由认为值为 1.0
的 float
将映射到 1
的 int
值。因此,您可以做的主要事情是按位运算,或依赖于理解用于 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
进行比较。这是因为 float
s 在 IEEE 格式中存储负数的方式与 2 的补码有很大不同:符号位实际上只是一个标志,表示值是正数还是负数,其余位存储大小的数量。应用 CV_TOGGLE_FLT(x)
后,您没有可以直接使用的值,但它们的排序方式与原始 float
值相同。
我试图了解 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* 真的安全吗,这个宏到底是做什么的?
提前致谢!
本质上,它以不可移植的方式对浮点数据进行一些二进制操作:对于 int
和 float
的相对大小以及关于他们的代表。我认为 if int
是一个 32 位的 2 的补码整数,而 float
是一个 IEEE 32 位浮点值,那么它可以让你比较仅使用整数运算的浮点值。
更详细...
int* ivalues = (int*)values;
这只是给了我们一个用于遍历浮点值的指针。它们被解释为ints
,而不是转换为int
——换句话说,没有理由认为值为 1.0
的 float
将映射到 1
的 int
值。因此,您可以做的主要事情是按位运算,或依赖于理解用于 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
进行比较。这是因为 float
s 在 IEEE 格式中存储负数的方式与 2 的补码有很大不同:符号位实际上只是一个标志,表示值是正数还是负数,其余位存储大小的数量。应用 CV_TOGGLE_FLT(x)
后,您没有可以直接使用的值,但它们的排序方式与原始 float
值相同。