Побитовый оператор & in Python - PullRequest
0 голосов
/ 25 мая 2020

Недавно я решал одну из самых базовых c задач на условных выражениях из Hackerrank.

Проблема была в следующем:

Если n нечетное, выведите Weird Если n четно и находится в диапазоне от 2 до 5, выведите Not Weird Если n четно и находится в диапазоне от 6 до 20, выведите Weird Если n четно и больше 20, выведите Not Weird

Итак, я написал следующий код

if(n % 2 == 0 & n >=6 & n <= 20 ):
    print("Weird")
elif(n % 2 == 0 & n <= 2 & n >= 5): 
     print("Not Weird")
elif( n % 2 != 0):
     print("Weird")
else:
     print("Not Weird")

Сначала он не работал. Я понял, что мне нужно было использовать «и» вместо «&». Но я не уверен, почему это произошло ... для n = 12 выполняются все 3 условия первого условия if. так что истина, истина и истина тоже должны быть истинными, верно?

на этой фотографии показан фрагмент кода с некоторыми сообщениями для печати

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

Ответы [ 4 ]

0 голосов
/ 25 мая 2020

Каждый раз, когда у вас возникают подобные сомнения, вы можете использовать модуль dis, в вашем случае я использую лямбда-функцию для оценки процесса:

func = lambda x: x % 2 == 0 & x >= 6 & x <= 20

это дает нам следующий дизассемблированный код :

              0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (2)
              4 BINARY_MODULO
              6 LOAD_CONST               2 (0)
              8 LOAD_FAST                0 (x)
             10 BINARY_AND
             12 DUP_TOP
             14 ROT_THREE
             16 COMPARE_OP               2 (==)
             18 JUMP_IF_FALSE_OR_POP    40
             20 LOAD_CONST               3 (6)
             22 LOAD_FAST                0 (x)
             24 BINARY_AND
             26 DUP_TOP
             28 ROT_THREE
             30 COMPARE_OP               5 (>=)
             32 JUMP_IF_FALSE_OR_POP    40
             34 LOAD_CONST               4 (20)
             36 COMPARE_OP               1 (<=)
             38 RETURN_VALUE
        >>   40 ROT_TWO
             42 POP_TOP
             44 RETURN_VALUE

объяснение просто:

  • Получить переменную x значение
  • Получить const 2 значение
  • Получить modulo сравнение между 2 и x, ответ 0, когда вы используете 12 в качестве значения параметра.
  • Получить const 0 значение
  • Получить var x значение
  • Получить двоичное and сравнение между 0 и x, естественно, побитовая операция между любым значением (например: b'1100') и b'0000' вернет 0.
  • Далее значения сохраняются в TOP и сравниваются с оператором ==. Это означает, что, как говорили другие ответы, (x % 2) == (0 & x) в это время, когда x является 12, переведенная операция 0 == 0 (True).
  • С проверкой результата ==, если это False ( в этом случае перейдите к строке 40 байт-кода), иначе удалите результат (POP) из TOS (верх стека)
  • Получите const 6 значение
  • Получите var x значение
  • Еще одно сравнение and, на этот раз между 6 (b'0110') и 12 (x = b'1100') с результатом 4 (b'0100')
  • Последний результат сохраняется в TOP и сравнивается с оператором >= с последним сохраненным значением (0 >= 4, как сказано в других ответах).
  • Ответ от 0 >= 4 тогда, оценивается в следующей инструкции, False вызывает переход кода непосредственно к инструкции 40 (Return False), даже не проверяя последний случай.

Конечно, это объяснение байт-кода для как работает python, краткий ответ - это 0 & n >= 6 & n, имея это в виду, мы можем предположить, что каждое число отличается от m 0 вернет False для этой оценки, потому что побитовая операция между b'0110' всегда будет больше 0.

TL; DR

Побитовые операторы оцениваются перед логическими операторами.

Каталожные номера

https://docs.python.org/3.8/library/dis.html Ссылка на модуль Dis.

0 голосов

Я настроил ваш код, и он работает. Вы можете применить этот код.

n = int(input("Enter n : "))

if(n%2 != 0):
    print("Weird")

elif(n%2 == 0 and n >= 2 and n <= 5): 
     print("Not Weird")

elif(n%2 == 0 and n >=6 and n <= 20 ):
    print("Weird")

else:
    print("Not Weird")
0 голосов
/ 25 мая 2020

Это может быть не сразу очевидно из грамматики , но двоичные арифметические операции c связываются сильнее, чем двоичные побитовые операции. Таким образом, ваше сравнение такое же, как

>>> if(n % 2 == (0 & n) >= (6 & n) <= 20 ):
...     print("Weird")
... 
>>>

Ваш случай «истина, истина и истина»:

>>> if((n % 2 == 0) & (n >=6) & (n <= 20) ):
...     print('Weird')
... 
Weird

Но это работает только потому, что python True и False оценивают на 1 и 0. Побитовая операция работает только из-за этого базового представления.

0 голосов
/ 25 мая 2020

для n = 12, все 3 условия первого условия если истинны.

>>> n = 12
>>> n % 2 == 0 & n >= 6 & n <= 20
False

Второе условие ложно (и условия не такие, как вы думаете, они являются, потому что побитовые операторы похожи на другие числовые c операторы [+, -, % и т. д.] в том, что они имеют более высокий приоритет, чем операторы сравнения).

Давайте разберем это немного:

>>> n % 2
0
>>> 0 & n
0
>>> 6 & n
4
>>> 0 == 0 >= 4 <= 20
False

Выражение ложно из-за условия 0 & n >= 6 & n. 0 не больше 4!

...