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

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

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

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

      01101010 & 01011001 = 01001000 

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

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

    ИЛИ означает «если включен 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 с использованием логики И. Все остальные биты фактически игнорируются, потому что ничего, и ничто не является ничем. Четное число в двоичном выражении равно четному числу в десятичной нотации (10 кратно 2).

    Другие фундаментальные операции с двоичными системами включают NOT и XOR. NOT означает «если A выключен» и является единственной формой логических ворот, которая принимает только один сигнал или «параметр» вместо двух. 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 float сначала будут неявно преобразованы в целые числа. Номера за пределами диапазона, которые могут быть выражены как целые числа, будут усечены до нуля – то есть все числа над PHP_INT_MAX будут выглядеть «четными» в выражении ($num & 1) ). Если вы хотите поддерживать номера за пределами PHP_INT_MIN / PHP_INT_MAX, вам понадобится fmod($num, 2) . Если, однако, вы на 64-битном PHP, ваши целые числа будут иметь большую точность, чем плавающие в любом случае.

    Это также интересно узнать о побитом и 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 

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

     if(func1() && func2()) 

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

     if(func1() & func2()) 

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


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

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

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

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