Подтвердить что ты не робот

Значение PHP Infinit в побитовых операциях возвращает странные значения

Сегодня я просто сделал интересное открытие, проверяя, что происходит, вычисляя битво в php, как INF ^ 0 (^ = > Побитовый оператор для исключительного ИЛИ (XOR)), что дало мне int(-9223372036854775808) = > наибольшее возможное отрицательное значение в 64-битная система.

Но потом я спрашивал себя: "Почему результат будет отрицательным в XOR, когда" положительный бесконечность "означает 9223372036854775807 (63 бита на 1 с ведущим 0) и 0 (64 бита на 0 = > 0 xor 0 = 0) Что такое бесконечное значение PHP, хотя и что за ним вычисляется? И почему я получаю (правильное?) отрицательное значение, когда я использую" отрицательный бесконечный "(A 1 против ведущего 0 на 0 = > 1 xor 0 = 1?".

Еще один интересный момент в том, что это происходит только на PHP версии 5.5.9-1, а не напр. на 5.3.x. и 5.6.x(где я его протестировал)! Может, у кого-то есть идея, что там происходит? Протестировано в трех версиях, но только мои (5.5.9-1) дают такие результаты:

Побитовые операции

Просто, чтобы вы, ребята, знали, это просто абстрактный игровой процесс, который я сделал для удовольствия, но мне это интересно. Может быть, кто-то может помочь здесь или объяснить мне неправильную мысль? Просто скажите, нужно ли кому-то больше информации о чем угодно!

EDIT: В соответствии с jbafford было бы здорово получить полный ответ, поэтому я просто процитирую его: why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?

4b9b3361

Ответ 1

Во-первых, ^ сам по себе не является чем-то особенным здесь. Если у вас XOR что-либо с нулем или OR с нулем, вы просто возвращаете исходный ответ. То, что вы видите здесь, не является частью самой операции, а скорее, что происходит до операции: побитовые операторы принимают целые числа, поэтому PHP преобразует float в целое число. Это в преобразовании float-to-integer, которое появляется странным поведением, и оно не является исключительным для побитовых операторов. Это также происходит, например, для (int).

Почему он производит эти странные результаты? Просто потому, что то, что написано в C-коде PHP, возникает при преобразовании float в целое число. В стандарте C поведение C для преобразований с плавающей точкой в ​​целое число составляет undefined для специальных значений INF, -INF и NAN (или, более точно, для "неотъемлемых частей" целое число не может представляют: §6.3.1.4). Это undefined поведение означает, что компилятор может делать все, что захочет. Просто так происходит в этом случае, что генерируемый им код генерирует здесь минимальное целочисленное значение, но нет никакой гарантии, что это всегда произойдет, и это не согласовано между платформами или компиляторами. 1 Почему изменилось поведение между 5.4 и 5.5? Потому что PHP-код для преобразования float в целые числа изменен, чтобы всегда выполнять преобразование по модулю. Это фиксировало поведение undefined для очень больших чисел с плавающей запятой, 2 но оно по-прежнему не проверяло специальные значения, поэтому в этом случае оно все еще создавало поведение undefined, немного отличающееся от этого время.

В PHP 7 я решил очистить эту часть поведения PHP с помощью Integer Semantics RFC, что делает PHP проверкой на специальные значения (INF, -INF и NAN) и конвертировать их последовательно: они всегда преобразуются в целое число 0. Здесь больше не работает undefined поведение.


1 Например, тестовая программа, которую я написал в C, чтобы попытаться преобразовать бесконечность в целое число (в частности, C long), имеет разные результаты в 32-битной и 64-битной сборках. 64-разрядная сборка всегда создает -9223372036854775808, минимальное целочисленное значение, а 32-разрядная сборка всегда создает 0. Такое поведение для GCC и clang одинаково, поэтому я думаю, что оба они производят очень похожий машинный код.

2 Если вы попытались преобразовать float в целое число, и это значение float было слишком большим, чтобы соответствовать целому числу (например, PHP_INT_MAX * 2 или PHP_INT_MIN * 2), результат был undefined. PHP 5.5 делает результат согласованным, хотя и неинтуитивным (он действует, если float был преобразован в очень большое целое число, а наиболее значимые бит были отброшены).

Ответ 2

Ваш float(INF) получает неявное выражение в Integer.

и XOR с 0 не изменяет первый параметр. Таким образом, в основном это всего лишь бросок от float до int, который undefined для значений, которые не находятся в целочисленном диапазоне. (для всех остальных значений он будет усечен до нуля)

https://3v4l.org/52bA5