Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737 Форумы портала PHP.SU :: Приложение к уроку № 1 - работа с битами
Покинул форум
Сообщений всего: 7540
Дата рег-ции: Янв. 2010 Откуда: Чернигов
Помог: 299 раз(а)
PHP как и многие другие языки поддерживает побитовые операции, их можно посмотреть тут.
Но просто посмотреть не достаточно. Если вы до этого не работали с ними (в других языках) то понять их будет очень сложно, в этой теме я постараюсь объяснить что они из себя представляют и как ими пользоватся.
Начём с того что в компьютерном мире любой символ представлен в виде последовательности битов (8 бит это 1 байт). Биты могут состоять только из 0 или 1. В 32 битных системах тип int занимает 4 байта в памяти (32/8) и может хранить число от -2147483648 до 2147483647. Откуда берутся эти ограничения тоже постараюсь обьяснить в этой теме.
Для того что бы всё понять я напишу биты чисел от 0 до 20, далее на них и будут показаны все примеры. Поскольку будем брать числа только до 20 то я возьму 8 бит (больше нету смысла там будут одни нули).
Как Вы можите заметить, каждое слещующее число в битовом представлении это обычное число но состоящее только из 0 и 1, тоесть 1, после еденицы из нулей и едениц идёт 10, после десяти 11, затем 100, 101, и т.д.
Примечание: всё побитовые операторы возвращают число.
1) $a & $b - Побитовое 'и'. Устанавливаются только те биты, которые установлены и в $a, и в $b.
Для примера возьмём число 7 и 14.
Но почем имено 6? Вот сейчас и разберёмся. Берём биты числа 7 и 14, и как написано в описанни оператора устанавливаем те биты которые есть и у 7 и у 14.
0000 0111 - 7
0000 1110 - 14
0000 0110 - и эти самые биты которые совпали, это и есть биты числа 6.
Ещё пример:
0000 1010 - 10
0000 1111 - 15
0000 1010 - 10
Где может быть полезен этот оператор? Результат не может быть больше меньшего числа, тоесть если 10 & (любое число), то результат в любом случае не будет больше 10, это можно применить например если у нас есть масив из 10 символов и пользователь может выбрать одно из них, но он же может ввести 11 например и будет ошибка, а если использовать этот оператор то за пределы масива мы точно не выйдем.
Снова берём биты 7 и 14, но теперь устанавливаем те биты которые есть у 7 либо у 14. Тоесть просто берём биты 7 и по верху накладываем биты 14.
0000 0111 - 7
0000 1110 - 14
0000 1111 - 15
Ещё пример
0000 0101 - 5
0000 1000 - 8
0000 1101 - 13
Где может пригодится этот оператор? Ну самый лучший пример это уровни ошибок в PHP (которые устанавливатся функцией error_reporting()), константы ошибок (E_NOTICE, E_WARNING, и т.д) содержат в себе число, которое имеет только 1 бит (1,2,4,8,16, и т.д) и когда вы совмещаете эти биты каждый бит занимает свою позицию и они не мешают друг другу.
0000 0001 - 1
0000 0010 - 2
0000 0100 - 4
0000 1000 - 8
0001 0000 - 16
А если совместить все то будет
0001 1111
и затем их можно просто разделить и узнать значения. Это полезно тем что в 32 битном числе можно хранить 32 булевых значения.
3) $a ^ $b - Исключающее 'или'. Устанавливаются только те биты, которые установлены либо только в $a, либо только в $b
Я думаю вы уже поняли как работать с битами поэтому просто пару примеров.
00000111 - 7
00001011 - 11
00001100 - 12
Где может быть полезен этот оператор? Ну вернёмся к тем же ошибкам в php, если мы хотим включить все ошибки кроме E_NOTICE, нам не нужно перечислять все 11 констант, а достаточно просто исключить из E_ALL ^ E_NOTICE.
4) ~ $a - Отрицание. Устанавливаются те биты, которые в $a не установлены, и наоборот.
Этот оператор можно сказать выворачивает биты на изнанку.
немогу прям так сказать где можно применить этот оператор, но иногда он нужен. Если заинтересуетесь побитовыми операциями то найдёте ему применение.
5) $a << $b - Сдвиг влево - Все биты переменной $a сдвигаються на $b позиций влево (каждая позиция подразумевает 'умножение на 2')
Здесь всё просто, все биты сдвигаются влево на $b позиций, и $b позиций слева заполняются нулями.
0000 0110 - 6
0000 1100 - 12
Так совпало что каждый здвиг влево умножает число на 2.
Точно по такому же принципу работет и Сдвиг вправо.
$a >> $b - Сдвиг вправо. Все биты переменной $a сдвигаються на $b позиций вправо (каждая позиция подразумевает 'деление на 2')
Сдвигает биты вправо на $b позиций и заполняет $b позиций слева нулями.
0001 0011 - 19
0000 1001 - 9
Куда можно применить эти 2 оператора? Они часто применятся на пару с "&" или "|", чуть ниже я покажу пример.
Ну вот мы немножко разобрались в побитовых опарациях и теперь что бы их закрепить надо что то написать.
Я решил показать как можно узнать биты любого числа с помощью побитовых операций. Начнём
Что бы узнать установлен ли бит можно пользоватся побитовым "и"
Почему имено 1 и 0? Снова обратимся к битам
0000 0001 - 1
0000 0011 - 3
0000 0001 - 1 // совпал 1 бит, и получилось число 1
0000 0001 - 1
0000 0100 - 4
0000 0000 - 0 // нет совпадений битов и поэтому 0
А как же нам теперь так проделать со всеми битами? Неужеле число надо поочереди сравнивать с 1,2,4,8,16, и т.д.? Нет, вот для этогои нужен здвиг.
Создадим цикл for, из 32 итераций (для 32 битного числа), и за каждую итерацию цикла мы будем проверять первый бит и здвигать на $i позиций вправо, а результат записывать в строку.
А вот как будет проходить каждая итерация цикла. (я убрал 24 левых бита, там все равно нули)
[1 итерация] Сдвигает на 0 позиций и сравниваем биты с еденицей.
0010 1011 - 43
0010 1011 - 43
0000 0001 - 1
// разультат
0000 0001 - 1
[2 итерация] Сдвигает на 1 позицию и сравниваем биты с еденицей.
0010 1011 - 43
0001 0101 - 21
0000 0001 - 1
// разультат
0000 0001 - 1
[3 итерация] Сдвигает на 2 позиции и сравниваем биты с еденицей.
0010 1011 - 43
0000 1010 - 10
0000 0001 - 1
// разультат
0000 0000 - 0
и т.д.
Таким же способом можно работать с большими числами.
Надеюсь эта статья кому то помогла.
Все гости форума могут просматривать этот раздел. Только зарегистрированные пользователи могут создавать новые темы в этом разделе. Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.