Что означает это логическое «(число & 1) == 0»?


79

На CodeReview я разместил рабочий фрагмент кода и попросил совета по его улучшению. Один из них заключался в использовании логического метода, чтобы проверить, имеет ли ArrayList четное количество индексов (что было необходимо). Это был предложенный код:

private static boolean isEven(int number)
{
    return (number & 1) == 0;
}

Поскольку я уже приставал к этому конкретному пользователю с просьбой о большой помощи, я решил, что пора приставать к сообществу SO! Я действительно не понимаю, как это работает. Метод вызывается и принимает размер ArrayList в качестве параметра (т.е. ArrayList имеет десять элементов, число = 10).

Я знаю, что один &запускает сравнение как числа, так и 1, но после этого я заблудился.

Я прочитал это так: return true if number == 0and 1 == 0. Я знаю, что первое неверно, а второе, очевидно, не имеет смысла. Может ли кто-нибудь мне помочь?

Изменить: я, вероятно, должен добавить, что код действительно работает, если кому-то интересно.


2
Кто-нибудь знает, кто связал это с другим постом (который не имеет к этому никакого отношения)? Можно как-нибудь удалить?
Эндрю Мартин

1
Черт, это действительно действительно умно!
cauon

2
Об этом было написано в Твиттере.
Джонатон Рейнхарт


1
@GrijeshChauhan Не могли бы вы уточнить, как это быстрее, чем number % 2 == 0??
Врушанк

Ответы:


114

Имейте в виду, что «&» - это побитовая операция. Вы, вероятно, знаете об этом, но мне это не совсем понятно, исходя из того, как вы задали вопрос.

При этом теоретическая идея состоит в том, что у вас есть некоторый int, который может быть выражен в битах некоторой серией единиц и нулей. Например:

...10110110

В двоичном формате, поскольку это основание 2, всякий раз, когда побитовая версия числа заканчивается на 0, оно четное, а когда оно заканчивается на 1, оно нечетное.

Следовательно, побитовое & с 1 для приведенного выше:

...10110110 & ...00000001

Конечно, это 0, так что можно сказать, что исходный ввод был четным.

Как вариант, рассмотрите нечетное число. Например, добавьте 1 к тому, что у нас было выше. потом

...10110111 & ...00000001

Равно 1 и, следовательно, не равно нулю. Вуаля.


13
Спасибо - ваше объяснение очень ясно. Кроме того, любой ответ, заканчивающийся на "Вуаля", заслуживает одобрения.
Эндрю Мартин

1
Вероятно, также следует помнить об отрицательных числах в этом ответе.
Элвин Вонг

3
Кроме того, я бы, возможно, исправил этот ответ, включив в него фактоид, что n%k == n&(k-1)для всех, kкоторые являются положительной силой 2. Возможно, это не то, о чем спрашивает спрашивающий, но это полезно знать.
пушистый

1
@fluffy не говорит, что это не сработает, но не все знают дополнение двух.
Элвин Вонг

1
@fluffy не должно ли в этом выражении быть logили 2^где-нибудь?
Navin

67

Вы можете определить четное или нечетное число по последнему биту в его двоичном представлении:

1 -> 00000000000000000000000000000001 (odd)
2 -> 00000000000000000000000000000010 (even)
3 -> 00000000000000000000000000000011 (odd)
4 -> 00000000000000000000000000000100 (even)
5 -> 00000000000000000000000000000101 (odd)
6 -> 00000000000000000000000000000110 (even)
7 -> 00000000000000000000000000000111 (odd)
8 -> 00000000000000000000000000001000 (even)

& между двумя целыми числами стоит побитовый оператор И:

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

Так что если (number & 1) == 0 есть true, значит numberэто чётно.


Предположим, что number == 6 тогда:

6 -> 00000000000000000000000000000110 (even)

     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

1 -> 00000000000000000000000000000001

-------------------------------------

0 -> 00000000000000000000000000000000

и когда number == 7:

7 -> 00000000000000000000000000000111 (odd)

     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

1 -> 00000000000000000000000000000001

-------------------------------------

1 -> 00000000000000000000000000000001

18

& - побитовый оператор И. &&является логическим оператором И

В двоичной системе, если установлен разряд цифр (т.е. единица), число нечетное.

В двоичном формате, если разряд цифр равен нулю, число четное.

(number & 1) является побитовым И проверкой разряда цифр.

Другой способ сделать это (возможно, менее эффективный, но более понятный) - использовать оператор модуля %:

private static boolean isEven(int number)
{
    if (number < 0)
       throw new ArgumentOutOfRangeException();

    return (number % 2) == 0;
}

2
&также логическое И. &&коротких замыканий пока &нет.
Стив Куо

5
number % 2это не то же самое, что number & 1если numberотрицательно.
dan04

4
если вам передается отрицательная длина, то у вас большие проблемы! ;)
Mitch Wheat

4
@RyanAmos "Перебирать каждый бит?" Побитовое И - это отдельная операция в каждом ЦП, которую я когда-либо видел - это одна из самых простых операций, выполняемых параллельно.
пушистый

2
@MitchWheat Нет причин бросаться на этот number < 0случай - в то время как мод 2 для нечетного отрицательного числа равен -1, четный модуль 2 по-прежнему равен 0.
fluffy

8

Это выражение означает «целое число представляет собой четное число».

Вот причина , почему: двоичное представление десятичного 1является 00000000001. Все нечетные числа в 1двоичном формате заканчиваются на (это легко проверить: предположим, что двоичное представление числа не заканчивается 1; тогда оно состоит из ненулевых степеней двойки, которые всегда являются четным числом). Когда вы делаете бинарный ANDс нечетным числом, то результат 1; когда вы делаете двоичный код ANDс четным числом, результат будет 0.

Раньше это был предпочтительный метод определения четности и нечетности в те времена, когда оптимизаторы были плохи или отсутствовали, а %операторы требовали в двадцать раз больше циклов, чем у &оператора. В наши дни, если вы это сделаете number % 2 == 0, компилятор, скорее всего, сгенерирует код, который выполняется так же быстро, как и (number & 1) == 0делает.


5

Single &означает побитовый andоператор not сравнение

Таким образом, этот код проверяет, установлен ли первый bit(наименее значащий / самый правый) или нет, что указывает, установлен ли номер odd; потому что все нечетные числа заканчиваются 1младшим битом, напримерxxxxxxx1


Обратите внимание, что сингл &может использоваться как логический, andесли вы хотите уберечь побочные эффекты от таких выражений, какf(x) & g(x)
Navin

4

&это побитовая ANDоперация.

Для числа = 8:

  1000
  0001
& ----
  0000

Результат таков (8 & 1) == 0. Это справедливо для всех четных чисел, поскольку они кратны 2, а первая двоичная цифра справа всегда 0. 1 имеет двоичное значение 1 с ведущими нулями, поэтому, когда мы ANDиспользуем четное число, мы остаемся с 0.


3

&Оператор в Java является побитовым и оператором. По сути, (number & 1)выполняет побитовое и между numberи1 . Результат будет либо 0, либо 1, в зависимости от того, четный он или нечетный. Затем результат сравнивается с 0, чтобы определить, четный ли он.

Вот страница, описывающая побитовые операции .


3

Он выполняет двоичное и против 1, которое возвращает 0, если младший значащий бит не установлен.

для вашего примера

00001010 (10)

00000001 (1)

===========

00000000 (0)


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.