今天,我在测试php中像INF ^ 0
(^
=>“异或”(XOR)的按位运算符)时按位计算时会发生什么时发现了一个有趣的发现,这给了我int(-9223372036854775808)
=>在64位系统中的最大可能负值。
但是后来我问自己:“为什么当“正无穷大”表示9223372036854775807
(在1
上为63位,在前面是0
)且结果为0(在0
上为64位=> 0 xor 0 = 0
),结果为什么在XOR中为负?PHP的无限值是多少但是,其背后的计算是什么?为什么当我使用“负无穷大”(0时领先的1
与0上的领先0
=> 1 xor 0 = 1
时,我得到一个(正确的)负值?
另一个有趣的一点是,这仅发生在PHP 5.5.9-1版本上,而不是例如在5.3.x上。和5.6.x(在我测试过的地方)!也许有人知道那里发生了什么?在三个版本上对其进行了测试,但只有我的版本(5.5.9-1)可以得出以下结果:
只是想让大家知道,这只是我玩得很开心的抽象玩法,但我发现它很有趣。也许有人可以在这里提供帮助或向我解释我的错误想法?只要告诉我是否有人需要更多有关任何信息!
编辑:因此,对jbafford来说,得到一个完整的答案将是很棒的,所以我只引用他:why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?
最佳答案
首先,^
本身在这里并不是什么特别的。如果对任何零进行异或,或者对零进行异或,则只需返回原始答案即可。您在这里看到的不是操作本身的一部分,而是操作之前发生的事情:按位运算符采用整数,因此PHP将float转换为整数。奇怪的行为出现在浮点数到整数的转换中,并且不是按位运算符独有的。例如,它也发生在(int)
上。
为什么会产生这些奇怪的结果?仅仅是因为这就是将浮点数转换为整数时PHP编写的C代码所产生的结果。在C标准中,对于INF
,-INF
和NAN
的特殊值(或更准确地说,对于“整数部分”,整数不能表示:§6.3.1.4),未定义C用于浮点数到整数转换的行为。此undefined behaviour表示编译器可以自由执行任何所需的操作。在这种情况下,恰好会发生这种情况,即它生成的代码会在此处产生最小的整数值,但是并不能保证会一直发生,并且在平台或编译器之间不一致。1为什么行为在5.4和5.5之间变化?因为PHP的转换代码将浮点数转换为整数changed to always perform a modulo conversion。这解决了非常大的浮点数2的不确定行为,但是它仍然没有检查特殊值,因此在这种情况下,它仍然产生不确定行为,这次只是稍有不同。
在PHP 7中,我决定使用Integer Semantics RFC清理PHP的这一部分行为,这使PHP检查特殊值(INF
,-INF
和NAN
)并一致地进行转换:它们始终转换为整数0
。这里不再存在未定义的行为。
1例如,我用C编写的试图将Infinity转换为整数(特别是C long
)的测试程序在32位和64位版本上具有不同的结果。 64位构建始终生成-9223372036854775808
(最小整数值),而32位构建始终生成0
。 GCC和clang的行为相同,因此我想它们都在产生非常相似的机器代码。
2如果您尝试将浮点数转换为整数,并且该浮点数的值太大而无法容纳整数(例如PHP_INT_MAX * 2
或PHP_INT_MIN * 2
),则结果不确定。 PHP 5.5使结果一致,尽管不直观(如果将float转换为非常大的整数,并且丢弃了最高有效位,则会起作用)。