Понимание оператора PHP & (амперсанд, побитовое и)

Я часто использую ($var & 1) в своем коде, который возвращает истину, если $var это нечетное число, и ложь, если это четное число.

Но что на самом деле делает «&»?

Ответов (5)

Решение

& является двоичным and . Если у вас есть двоичное значение, а у вас and другое двоичное значение, то результат будет побитовым and из двух. Пример:

  01101010
& 01011001
= 01001000

Крайний правый бит - это либо 1 (и в этом случае число является нечетным), либо 0, и в этом случае число четное. Если у вас & число с 1, вы смотрите только на младший значащий бит, а if проверяет, является ли число 1 или 0. Как уже упоминалось, посмотрите на побитовые операторы для получения информации о том, как они работают.

Также интересно узнать о побитовых вычислениях и PHP:

/**
 * Regular
 */
echo (true && true); // 1
echo (true && false); // nothing

echo (true || false); // 1
echo (false || false); // nothing

echo (true xor false); // 1
echo (false xor false); // nothing

/**
 * Bitwise
 */
echo (true & true); // 1
echo (true & false); // 0

echo (true | false); // 1
echo (false | false); // 0

echo (true ^ false); // 1
echo (false ^ false); // 0

Две операции, которые являются фундаментальными для двоичных систем, - это ИЛИ и И.

ИЛИ означает «если включен A или включен B». Пример из реальной жизни - два переключателя, включенных параллельно. Если какой-либо из них пропускает ток, значит, ток проходит.

И означает «если включены и A, и B». Пример из реальной жизни - два последовательно включенных переключателя. Ток будет проходить только в том случае, если оба пропускают ток.

В компьютере это не физические переключатели, а полупроводники, и их функции называются логическими вентилями . Они делают то же самое, что и переключатели - реагируют на ток или отсутствие тока.

Применительно к целым числам каждый бит одного числа объединяется с каждым битом другого числа. Итак, чтобы понять побитовые операторы OR и AND, вам нужно преобразовать числа в двоичные, а затем выполнить операцию OR или AND для каждой пары совпадающих битов.

Поэтому:

00011011 (odd number)
AND
00000001 (& 1)
== 
00000001 (results in 1)

В то время как

00011010 (even number)
AND
00000001 (& 1)
==
00000000 (results in 0)

Поэтому операция (& 1) сравнивает самый правый бит с 1 с помощью логики AND. Все остальные биты игнорируются, потому что все И ничто - ничто. Четное число в двоичной системе счисления также является четным числом в десятичной системе счисления (10 кратно 2).

Другие фундаментальные операции с двоичными системами включают NOT и XOR. НЕ означает «если А выключен» и является единственной формой логического элемента, которая принимает только один сигнал или «параметр» вместо двух. XOR означает «если включен либо A, либо B, но не оба». И еще есть NAND, NOR и NXOR, которые в основном просто НЕ комбинируются с AND, OR и XOR, т.е. NAND означает «если A и B не включены одновременно».

В программировании оператор

& means AND,
| means OR, 
~ means NOT, and
^ means XOR.

Остальные можно составить, объединив их, например:

~ (a & b) is equivalent to a NAND operation

Замечание по PHP

Побитовые операторы не работают со значениями с плавающей запятой, и в PHP значения с плавающей запятой сначала неявно преобразуются в целые числа. Числа вне диапазона, которые могут быть выражены как целые числа, будут усечены до нуля - то есть все числа, превышающие PHP_INT_MAX, будут выглядеть в выражении «четными» ($num & 1) ). Если вы хотите поддерживать числа вне PHP_INT_MIN / PHP_INT_MAX, вам понадобится fmod($num, 2) . Однако, если вы используете 64-битный PHP, ваши целые числа в любом случае будут иметь большую точность, чем числа с плавающей запятой.

Я знаю, что ваш вопрос касается понимания побитового оператора, и принятый ответ хорошо его объясняет. Но в приведенном вами примере я не могу не рекомендовать вам использовать вместо этого оператор по модулю:

($var % 2) /* instead of */ ($var & 1)

Поскольку это проясняет намерение, вы проверяете, что число нечетное (не делится на два), и оно является более общим, поэтому вы можете использовать ($ var% 3) таким же образом и вывести, как это работает для любого N.

В дополнение к другим ответам стоит отметить, что

if(func1() && func2())

Будет вызываться только в том func2() случае, если func1() возвращается истина («ленивая оценка»), тогда как

if(func1() & func2())

Независимо от вызова будет вызывать обе функции, но таблицы истинности для обеих будут одинаковыми (при условии, что они возвращают логические значения).


thomasrutter указывает (в комментариях ниже), что вам, вероятно, не следует делать последнее на практике. (A & B) не обязательно будет иметь такую ​​же правдивость, как (A && B), особенно когда A и B являются целыми числами. например, если A = 1 и B = 2 (оба правдивы), A и B будут ложными, тогда как A && B правдивыми. Кроме того, другой разработчик может подумать, что это опечатка, и «поправить» ее до двух амперсандов.