我试图理解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 */
}
有谁知道这里发生了什么?将浮点*强制转换为int *是否真的安全,宏实际上做了什么?
提前致谢!
答案 0 :(得分:2)
本质上,它以非可移植的方式对浮点数据进行一些二进制操作:显然有关于int
和float
的相对大小的假设以及它们的表示。我认为如果 int
是32位二进制补码整数,float
是IEEE 32位浮点值,那么它可以让你比较浮点数值只使用整数运算。
更详细......
int* ivalues = (int*)values;
这只是给我们一个用于遍历浮点值的指针。它们被解释为为ints
,而非已转换为int
- 换句话说,没有理由认为float
与值1.0
将映射到int
1
的值。因此,您可以做的主要是按位操作或依赖于理解用于float
的二进制格式的特定操作。
看宏......
#define CV_TOGGLE_FLT(x) ((x)^((int)(x) < 0 ? 0x7fffffff : 0))
值x
(记住,只是其中一些代表浮点值的位,但我们只是将它看作一个位模式)与0
进行异或运算(没有效果)或0x7fffffff
(反转低位31位)。决定做什么是基于x
是否小于零。
我认为这个宏是基于int
是32位二进制补码表示的假设。这意味着如果设置了最高位,则x < 0
为真。带0x7fffffff
的XOR将反转其他位。这意味着-1
,最正的负数,从0xffffffff
更改为0x8000000
,这是最负的负数(-2147483648
),同样{{1变成0x8000000
。在此之后使用0xffffffff
来比较两个负数时,这意味着更多负面数字现在是更多正面数字,而“更大比“将采取分支。比较两个正数是不变的,并且将正数与负数进行比较,正数正如您所期望的那样,仍然总是更大。
这使您可以仅使用整数运算对>
进行比较。这是因为IEEE格式的float
存储负数的方式与2的补码完全不同:符号位实际上只是一个值为正或负的标志,其余的位存储幅度数量。应用float
后,您没有可以直接使用的值,但它们的排序方式与原始CV_TOGGLE_FLT(x)
值相同。