PHP 在按位运算中的 Infinit 值返回奇怪的值

2022-08-30 23:40:27

今天,我刚刚在测试php中按位计算发生的事情时发现了一个有趣的发现,例如( => Exclusive OR (XOR)的按位运算符)在64位系统中给了我=>最大的负值。INF ^ 0^int(-9223372036854775808)

但后来我问自己:“为什么在XOR中结果为负,而”正无穷大“的意思是(63位,前导)和0(64位在=>)PHP的无穷大值是什么,它背后的计算是什么?为什么当我使用“负无穷大”(A领先于0 = >上的领先者)时,我会得到一个(正确的?)负值?92233720368547758071000 xor 0 = 0101 xor 0 = 1

另一个有趣的观点是,这只是在PHP版本5.5.9-1上发生,而不是在5.3.x.和5.6.x(我已经测试过的地方)!也许有人知道那里发生了什么?在三个版本上进行了测试,但只有我的(5.5.9-1)给出了这些结果:

Bitwise operations

只是为了让你们知道,这只是我为了好玩而做的一个抽象的游戏,但我发现它很有趣。也许有人可以在这里帮忙,或者向我解释一个错误的想法?如果有人需要有关任何事情的更多信息,请告诉我!

编辑:因此,对于jbafford来说,得到一个完整的答案会很棒,所以我只引用他的话:why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?


答案 1

首先,这里本身并不特别。如果你用零或任何东西或零来XOR任何东西,你只会得到原始答案。您在这里看到的不是操作本身的一部分,而是操作之前发生的事情:按位运算符采用整数,因此PHP将浮点数转换为整数。在浮点数到整数的转换中,出现了奇怪的行为,并且它不是按位运算符所独有的。例如,它也发生在 。^(int)

为什么会产生这些奇怪的结果?仅仅因为这是编写C代码PHP在将浮点数转换为整数时产生的。在 C 标准中,对于 的特殊值,C 在浮点数到整数转换的行为中是未定义的,并且(或者更准确地说,对于整数不能表示的“整数部分”:§6.3.1.4)。这种未定义的行为意味着编译器可以自由地做任何它想做的事情。在这种情况下,它生成的代码在这里产生最小整数值,但不能保证这种情况总是会发生,并且在平台或编译器之间不一致。1 为什么行为在5.4和5.5之间发生了变化?因为 PHP 用于将浮点数转换为整数的代码更改为始终执行模转换。这修复了非常大的浮点数的未定义行为,2但它仍然没有检查特殊值,因此在这种情况下,它仍然产生未定义的行为,只是这次略有不同。INF-INFNAN

在 PHP 7 中,我决定使用 Integer Semantics RFC 清理 PHP 行为的这一部分,这使得 PHP 检查特殊值 (, and ) 并一致地转换它们:它们始终转换为整数 。这里不再有未定义的行为。INF-INFNAN0


1 例如,我用C编写的一个测试程序,试图将无穷大转换为整数(特别是C),在32位和64位构建上有不同的结果。64 位构建始终生成 最小整数值,而 32 位构建始终生成 。GCC和clang的这种行为是相同的,所以我想它们都产生了非常相似的机器代码。long-92233720368547758080

2 如果您尝试将浮点数转换为整数,并且该浮点数的值太大而无法放入整数(例如 ,或 ),则结果未定义。PHP 5.5 使结果保持一致,尽管不直观(如果浮点数转换为非常大的整数,并且丢弃了最重要的位,则它会起作用)。PHP_INT_MAX * 2PHP_INT_MIN * 2


答案 2

您的将隐式转换为整数。float(INF)

并且 0 的 XOR 不会更改第一个参数。所以基本上这只是从浮点数到int的强制转换,对于不在整数范围内的值是未定义的。(对于所有其他值,它将被截断为零)

https://3v4l.org/52bA5


推荐