此代码利用 IEEE 754 格式的结构来处理浮点数。该结构本身是专门为此类操作设计的,以便快速进行比较操作。
每个单精度 IEEE 754 数字包含三个部分(从 MSB 到 LSB 的顺序):
- 符号位
- 指数部分(8 位)
- 尾数的有效位(23 位)
f1
大于f2
如果:
f1
是正的和f2
负的
f1
并且f2
都是正数,但f1
指数大于f2
f1
并且f2
都是正数,并且具有相同的指数,但f1
有效数大于f2
f1
如果和f2
为负,则与前两个相反
如果它们是二进制补码表示,则可以将两个浮点数作为整数进行比较。不幸的是,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
为负,则其 MSB 为负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 都有专门的指令来在硬件中执行带符号的比较。