此代码利用浮点数的IEEE 754格式结构。该结构本身是专门为此类操作而设计的,以便快速进行比较操作。
每个单精度IEEE 754号有三个部分(为了从MSB到LSB):
- 符号位
- 指数部分(8个比特)
- 有效数尾数的(23个比特)
f1
大于f2
如果:
f1
为正,f2
为负
f1
和f2
都是积极的,但f1
具有更大的指数比f2
f1
和f2
均为正,并且具有相同的指数,但f1
比f2
- 大尾数前两个相反
f1
和f2
是负数
如果浮点数是two's complement表示形式,则可以将两个浮点数作为整数进行比较。不幸的是,IEEE 754不使用二进制补码来表示负数,这就是为什么此代码执行转换以便能够将数字作为有符号整数进行比较。
这里是什么样的每一行代码确实一步步解说:
i1 = *(int*)f1; // reading float as integer
i2 = *(int*)f2; // reading float as integer
这一次使用的事实,在大多数32位系统sizeof(int) == sizeof(float)
读取浮点数到正规签署整数变量。
t1 = i1 >> 31;
这一个提取f1
的符号位。如果f1
为负,则其最高有效位将为1
,因此i1
将为负值。将它向右移动31位可以保留符号,因此如果i1
为负数,则t1
的所有位都将设置为1
(等于-1)。如果f1
为正,它的符号位将为0
,最后t1
将等于0
。
i1 = (i1^t1) + (t1 & 0x80000001);
如果符号位为1
这条线将执行转换为二进制补码表示,如果f1
为阴性。
这里是它如何工作的:如果f1
呈阳性,那么t1
是0
和(i1^t1)
也只是i1
和(t1 & 0x80000001)
将0
并最终i1
将只保留其原始值。如果f1
为负数,则t1
将所有位设置为1
,并且RHS上的第一个表达式将是i1
的位反转,第二个表达式将等于0x80000001
。这种方式i1
将被转换为其位反转,并且将添加1
。但是这将导致一个正数,因为MSB将被清除,这就是为什么0x80000000
也被添加来保持数字为负。
t2 = i2 >> 31;
i2 = (i2^t2) + (t2 & 0x80000001);
对f2
执行与上述相同的操作。
return i1 > i2;
只是比较两个结果签署整数。大多数CPU都有专用指令来执行硬件中的带符号比较。
“但速度更快”。 - 比什么更快? –
我想你可能会拉[这个有点](http://stackoverflow.com/questions/10381927/efficient-floating-point-comparison-cortex-a8)。 – Bart
@Bart是的,我现在有一段时间在实际情况下尝试这些代码,但我仍然不明白它是如何工作的。 – Alex