Отрицание Hex в PHP, забавное поведение - PullRequest
9 голосов
/ 09 марта 2012

У меня странное поведение. Мне было интересно, может ли кто-нибудь помочь мне разобраться.

Проверьте это

$hex = 0x80008000;

print_r(decbin(intval($hex)) . '<br/>');
print_r(decbin($hex));

Выходы

10000000000000001000000000000000
10000000000000001000000000000000

Как и ожидалось.1009 *

Но

$hex = 0x80008000;

print_r(decbin(~intval($hex)) . '<br/>');
print_r(decbin(~$hex));

Выходы

1111111111111110111111111111111
1111111111111111111111111111111

Почему средний бит не переключается, когда $hex отрицается?

Ответы [ 2 ]

0 голосов
/ 12 марта 2012

Собираюсь дать ответ на мой собственный вопрос здесь.

Да, это 32-битная / 64-битная разница.

В 32-битных системах тип с плавающей запятой должен занимать два пространства памяти, чтобы получить необходимые 64 бита. Php использует двойную точность (см. http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers)

$ hex соответствует типу с плавающей точкой. Функции intval и decbin преобразуют это в тип int (1-й пример выше)

Во втором примере мы используем небитовый оператор ДО того, как мы используем decbin. Это сначала переворачивает биты с плавающей запятой с двойной точностью в два пространства памяти, а затем преобразуется во второе. Дает нам нечто отличное от того, что мы ожидали.

Действительно, если мы поместим отрицание внутри intval () примерно так:

$hex = 0x80008000;

print_r(decbin(intval(~$hex)) . '<br/>');
print_r(decbin(~$hex));

Получаем

1111111111111111111111111111111
1111111111111111111111111111111

Как вывод.

Я пока недостаточно хорош, чтобы доказать это с помощью математики (которую можно выяснить с помощью этой статьи http://en.wikipedia.org/wiki/Double_precision). Но, может быть, когда у меня будет время позже -_-

Я думаю, что очень важно узнать, как числа представлены в компьютерах, чтобы мы могли понимать подобные аномалии и не называть их ошибками.

0 голосов
/ 09 марта 2012

Возможно, случай подпадает под это:

Со страницы побитовых операторов php http://us3.php.net/manual/en/language.operators.bitwise.php

Оператор NOT или дополнения (~) и отрицательные двоичные числа могут сбивать с толку.

~ 2 = -3, потому что вы используете формулу ~ x = -x - 1 Побитовое дополнение десятичного числа - это отрицание числа минус 1.

ПРИМЕЧАНИЕ: только использование 4биты здесь для примеров ниже, но на самом деле PHP использует 32 бита.

Преобразование отрицательного десятичного числа (то есть: -3) в двоичное происходит за 3 шага: 1) преобразовать положительную версию десятичного числа в двоичное (т.е.: 3 = 0011) 2) переворачивает биты (то есть: 0011 становится 1100) 3) добавляет 1 (то есть: 1100 + 0001 = 1101)

Вам может быть интересно, как 1101 = -3.Хорошо, PHP использует метод "2'splement" для рендеринга отрицательных двоичных чисел.Если самый левый бит равен 1, то двоичное число отрицательно, и вы переворачиваете биты и добавляете 1. Если оно равно 0, то оно положительно и вам ничего не нужно делать.Таким образом, 0010 будет положительным 2. Если это 1101, оно отрицательное, и вы переворачиваете биты, чтобы получить 0010. Добавьте 1, и вы получите 0011, что равно -3.

...