今天,我在测试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)可以得出以下结果:

php - 按位操作中的PHP无限值返回奇怪的值-LMLPHP

只是想让大家知道,这只是我玩得很开心的抽象玩法,但我发现它很有趣。也许有人可以在这里提供帮助或向我解释我的错误想法?只要告诉我是否有人需要更多有关任何信息!

编辑:因此,对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-INFNAN的特殊值(或更准确地说,对于“整数部分”,整数不能表示:§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-INFNAN)并一致地进行转换:它们始终转换为整数0。这里不再存在未定义的行为。

1例如,我用C编写的试图将Infinity转换为整数(特别是C long)的测试程序在32位和64位版本上具有不同的结果。 64位构建始终生成-9223372036854775808(最小整数值),而32位构建始终生成0。 GCC和clang的行为相同,因此我想它们都在产生非常相似的机器代码。

2如果您尝试将浮点数转换为整数,并且该浮点数的值太大而无法容纳整数(例如PHP_INT_MAX * 2PHP_INT_MIN * 2),则结果不确定。 PHP 5.5使结果一致,尽管不直观(如果将float转换为非常大的整数,并且丢弃了最高有效位,则会起作用)。

07-24 09:44
查看更多