Текущее время: 23 апр 2024, 19:50

PHP

QuickSite@Kadet шаблон для создания маленьких сайтов

PHP

Сообщение kadet » 30 июл 2013, 21:19

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

Побитовые операторы позволяют считывать и устанавливать конкретные биты целых чисел.

Побитовые операторы
Пример Название Результат
$a & $b И Устанавливаются только те биты, которые установлены и в $a, и в $b.
$a | $b Или Устанавливаются те биты, которые установлены в $a или в $b.
$a ^ $b Исключающее или Устанавливаются только те биты, которые установлены либо только в $a, либо только в $b, но не в обоих одновременно.
~ $a Отрицание Устанавливаются те биты, которые не установлены в $a , и наоборот.
$a << $b Сдвиг влево Все биты переменной $a сдвигаются на $b позиций влево (каждая позиция подразумевает "умножение на 2")
$a >> $b Сдвиг вправо Все биты переменной $a сдвигаются на $b позиций вправо (каждая позиция подразумевает "деление на 2")
Побитовый сдвиг в PHP - это арифметическая операция. Биты, сдвинутые за границы числа, отбрасываются. Сдвиг влево дополняет число нулями справа, сдвигая в то же время знаковый бит числа влево, что означает что знак операнда не сохраняется. Сдвиг вправо сохраняет копию сдвинутого знакового бита слева, что означает что знак операнда сохраняется.

Используйте скобки для обеспечения необходимого. приоритета операторов. Например, $a & $b == true сначала проверяет на равенство, а потом выполняет побитовое и; тогда как ($a & $b) == true сначала выполняет побитовое и, а потом выполняет проверку на равенство.

Будьте в курсе преобразований типов. Если оба, и левый и правый оператор являются строками, побитовый оператор будет работать с ASCII значениями символов этих строк.

Опция настроек PHP error_reporting использует побитовые значения, обеспечивая реальную демонстрацию гашения значений битов.
Чтобы показать все ошибки, кроме замечаний, инструкции в файле php.ini предлагают использовать:
E_ALL & ~E_NOTICE

Начинаем со значения E_ALL:
00000000000000000111011111111111
Затем берем значение E_NOTICE...
00000000000000000000000000001000
... и инвертируем его с помощью ~:
11111111111111111111111111110111
Наконец, с помощью AND (&) узнаем биты, выставленные в единицу, в обоих значениях:
00000000000000000111011111110111

Другой способ достичь этого - использовать ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR, ^), чтобы получить только те биты, которые выставлены в единицу либо только в одном, либо только в другом значении:
E_ALL ^ E_NOTICE

error_reporting также может быть использована для демонстрации включения битов. Показать только ошибки и обрабатываемые ошибки можно следующим образом:
E_ERROR | E_RECOVERABLE_ERROR

Здесь мы комбинируем E_ERROR
00000000000000000000000000000001
и
00000000000000000001000000000000
с помощью оператора ИЛИ (OR, |), чтобы получить включенные биты в обоих значениях:
00000000000000000001000000000001

Пример #1 Операции с побитовыми И, ИЛИ и ИСКЛЮЧАЮЩИМ ИЛИ (AND, OR и XOR) на целых числах

Код: выделить все
<?php
/*
 * Не обращайте внимания на этот верхний раздел кода,
 * это просто форматирование для более ясного вывода.
 */

$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
        . ' %3$s (%4$2d = %4$04b)' . "\n";

echo <<<EOH
 ---------     ---------  -- ---------
 результат     значение   оп   тест
 ---------     ---------  -- ---------
EOH;


/*
 * Вот сами примеры.
 */

$values = array(0, 1, 2, 4, 8);
$test = 1 + 4;

echo "\n Побитовое И (AND) \n";
foreach ($values as $value) {
    $result = $value & $test;
    printf($format, $result, $value, '&', $test);
}

echo "\n Побитовое (включающее) ИЛИ (OR) \n";
foreach ($values as $value) {
    $result = $value | $test;
    printf($format, $result, $value, '|', $test);
}

echo "\n Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) \n";
foreach ($values as $value) {
    $result = $value ^ $test;
    printf($format, $result, $value, '^', $test);
}
?>

Результат выполнения данного примера:

--------- --------- -- ---------
результат значение оп тест
--------- --------- -- ---------
Побитовое И (AND)
( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101)
( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101)
( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101)
( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101)
( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101)

Побитовое (включающее) ИЛИ (OR)
( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101)
( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101)
( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) | ( 5 = 0101)

Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR)
( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101)
( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101)
( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)


Пример #2 Операции с побитовым ИСКЛЮЧАЮЩИМ ИЛИ (XOR) над строками

Код: выделить все
<?php
echo 12 ^ 9; // Выводит '5'

echo "12" ^ "9"; // Выводит символ Backspace (ascii 8)
                 // ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8

echo "hallo" ^ "hello"; // Выводит ascii значения #0 #4 #0 #0 #0
                        // 'a' ^ 'e' = #4

echo 2 ^ "3"; // Выводит 1
              // 2 ^ ((int)"3") == 1

echo "2" ^ 3; // Выводит 1
              // ((int)"2") ^ 3 == 1
?>

Пример #3 Сдвигание битов в целых числах

Код: выделить все
<?php
/*
 * Несколько примеров.
 */

echo "\n--- СДВИГ ВПРАВО В ПОЛОЖИТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---\n";

$val = 4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'копия знакового бита была сдвинута влево');

$val = 4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places);

$val = 4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'биты были сдвинуты за правый край');

$val = 4;
$places = 4;
$res = $val >> $places;
p($res, $val, '>>', $places, 'то же, что и выше; нельзя сдвинуть дальше 0');


echo "\n--- СДВИГ ВПРАВО В ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---\n";

$val = -4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'копия знакового бита была сдвинута влево');

$val = -4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places, 'биты были сдвинуты за правый край');

$val = -4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'то же, что и выше; нельзя сдвинуть дальше -1');


echo "\n--- СДВИГ ВЛЕВО В ПОЛОЖИТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---\n";

$val = 4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'правый край был дополнен нулями');

$val = 4;
$places = (PHP_INT_SIZE * 8) - 4;
$res = $val << $places;
p($res, $val, '<<', $places);

$val = 4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places, 'знаковые биты были сдвинуты');

$val = 4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'биты были сдвинуты за левый край');


echo "\n--- СДВИГ ВЛЕВО В ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---\n";

$val = -4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'правый край был дополнен нулями');

$val = -4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places);

$val = -4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'биты были сдвинуты за левый край, включая знаковый бит');


/*
 * Не обращайте внимания на этот нижний раздел кода,
 * это просто форматирование для более ясного вывода.
 */

function p($res, $val, $op, $places, $note = '') {
    $format = '%0' . (PHP_INT_SIZE * 8) . "b\n";

    printf("Выражение: %d = %d %s %d\n", $res, $val, $op, $places);

    echo " Десятичный вид:\n";
    printf("  val=%d\n", $val);
    printf("  res=%d\n", $res);

    echo " Двоичный вид:\n";
    printf('  val=' . $format, $val);
    printf('  res=' . $format, $res);

    if ($note) {
        echo " ЗАМЕЧАНИЕ: $note\n";
    }

    echo "\n";
}
?>

Результат выполнения данного примера на 32-битных машинах:


--- СДВИГ ВПРАВО В ПОЛОЖИТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: 2 = 4 >> 1
Десятичный вид:
val=4
res=2
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000010
ЗАМЕЧАНИЕ: копия знакового бита была сдвинута влево

Выражение: 1 = 4 >> 2
Десятичный вид:
val=4
res=1
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000001

Выражение: 0 = 4 >> 3
Десятичный вид:
val=4
res=0
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были сдвинуты за правый край

Выражение: 0 = 4 >> 4
Десятичный вид:
val=4
res=0
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше 0


--- СДВИГ ВПРАВО В ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: -2 = -4 >> 1
Десятичный вид:
val=-4
res=-2
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111110
ЗАМЕЧАНИЕ: копия знакового бита была сдвинута влево

Выражение: -1 = -4 >> 2
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
ЗАМЕЧАНИЕ: биты были сдвинуты за правый край

Выражение: -1 = -4 >> 3
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше -1


--- СДВИГ ВЛЕВО В ПОЛОЖИТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: 8 = 4 << 1
Десятичный вид:
val=4
res=8
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000001000
ЗАМЕЧАНИЕ: правый край был дополнен нулями

Выражение: 1073741824 = 4 << 28
Десятичный вид:
val=4
res=1073741824
Двоичный вид:
val=00000000000000000000000000000100
res=01000000000000000000000000000000

Выражение: -2147483648 = 4 << 29
Десятичный вид:
val=4
res=-2147483648
Двоичный вид:
val=00000000000000000000000000000100
res=10000000000000000000000000000000
ЗАМЕЧАНИЕ: знаковые биты были сдвинуты

Выражение: 0 = 4 << 30
Десятичный вид:
val=4
res=0
Двоичный вид:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были сдвинуты за левый край



--- СДВИГ ВЛЕВО В ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: -8 = -4 << 1
Десятичный вид:
val=-4
res=-8
Двоичный вид:
val=11111111111111111111111111111100
res=11111111111111111111111111111000
ЗАМЕЧАНИЕ: правый край был дополнен нулями

Выражение: -2147483648 = -4 << 29
Десятичный вид:
val=-4
res=-2147483648
Двоичный вид:
val=11111111111111111111111111111100
res=10000000000000000000000000000000

Выражение: 0 = -4 << 30
Десятичный вид:
val=-4
res=0
Двоичный вид:
val=11111111111111111111111111111100
res=00000000000000000000000000000000

ЗАМЕЧАНИЕ: биты были сдвинуты за левый край, включая знаковый бит
Результат выполнения данного примера на 64-битных машинах:


--- СДВИГ ВПРАВО В ПОЛОЖИТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: 2 = 4 >> 1
Десятичный вид:
val=4
res=2
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000010
ЗАМЕЧАНИЕ: копия знакового бита была сдвинута влево

Выражение: 1 = 4 >> 2
Десятичный вид:
val=4
res=1
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000001

Выражение: 0 = 4 >> 3
Десятичный вид:
val=4
res=0
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были сдвинуты за правый край

Выражение: 0 = 4 >> 4
Десятичный вид:
val=4
res=0
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше 0


--- СДВИГ ВПРАВО В ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: -2 = -4 >> 1
Десятичный вид:
val=-4
res=-2
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111110

ЗАМЕЧАНИЕ: копия знакового бита была сдвинута влево

Выражение: -1 = -4 >> 2
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
ЗАМЕЧАНИЕ: биты были сдвинуты за правый край

Выражение: -1 = -4 >> 3
Десятичный вид:
val=-4
res=-1
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше -1


--- СДВИГ ВЛЕВО В ПОЛОЖИТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: 8 = 4 << 1
Десятичный вид:
val=4
res=8
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000001000
ЗАМЕЧАНИЕ: правый край был дополнен нулями

Выражение: 4611686018427387904 = 4 << 60
Десятичный вид:
val=4
res=4611686018427387904
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0100000000000000000000000000000000000000000000000000000000000000

Выражение: -9223372036854775808 = 4 << 61
Десятичный вид:
val=4
res=-9223372036854775808
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=1000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: знаковые биты были сдвинуты

Выражение: 0 = 4 << 62
Десятичный вид:
val=4
res=0
Двоичный вид:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
ЗАМЕЧАНИЕ: биты были сдвинуты за левый край


--- СДВИГ ВЛЕВО В ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ ---
Выражение: -8 = -4 << 1
Десятичный вид:
val=-4
res=-8
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111000

ЗАМЕЧАНИЕ: правый край был дополнен нулями

Выражение: -9223372036854775808 = -4 << 61
Десятичный вид:
val=-4
res=-9223372036854775808
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1000000000000000000000000000000000000000000000000000000000000000

Выражение: 0 = -4 << 62
Десятичный вид:
val=-4
res=0
Двоичный вид:
val=1111111111111111111111111111111111111111111111111111111111111100
res=0000000000000000000000000000000000000000000000000000000000000000

ЗАМЕЧАНИЕ: биты были сдвинуты за левый край, включая знаковый бит
Внимание
Не используйте сдвиг вправо более чем на 32 бита на 32-битных системах. Не используйте сдвиг влево для получения чисел, требующих для записи более 32 бит. Используйте функции из расширения gmp на числах, больших PHP_INT_MAX.
Я не родился - меня призвали.
Аватар пользователя
kadet
МС России
МС России
 
Сообщений: 110
Зарегистрирован: 15 июл 2010, 14:51
Откуда: Irkutsk

Вернуться в QuickSite@Kadet

Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

cron