비트 연산 및 사용


102

이 코드를 고려하십시오.

x = 1        # 0001
x << 2       # Shift left 2 bits: 0100
# Result: 4

x | 2        # Bitwise OR: 0011
# Result: 3

x & 1        # Bitwise AND: 0001
# Result: 1

나는 파이썬 (및 다른 언어)의 산술 연산자를 이해할 수 있지만 '비트'연산자를 잘 이해하지 못했습니다. 위의 예제 (Python 책에서 발췌)에서 왼쪽 시프트는 이해하지만 나머지 두 개는 이해하지 못합니다.

또한 실제로 비트 연산자는 무엇에 사용됩니까? 몇 가지 예를 고맙게 생각합니다.


11
이것이 흥미로울 수 있습니다. stackoverflow.com/questions/276706/what-are-bitwise-operators
2009

이것은 또한 관심이있을 수 있습니다 stackoverflow.com/questions/8556206/what-does-mean-in-python
필립 Oger 보낸

답변:


163

비트 연산자는 다중 비트 값에 대해 작동하지만 개념적으로는 한 번에 한 비트 씩 작동하는 연산자입니다.

  • AND 입력이 모두 1 인 경우에만 1이고, 그렇지 않으면 0입니다.
  • OR입력 중 하나 또는 모두 가 1이면 1이고 그렇지 않으면 0입니다.
  • XOR정확히 하나 의 입력이 1 인 경우 에만 1이고, 그렇지 않으면 0입니다.
  • NOT 입력이 0 인 경우에만 1이고, 그렇지 않으면 0입니다.

이들은 종종 진리표로 가장 잘 표시 될 수 있습니다. 입력 가능성은 상단과 왼쪽에 있으며, 결과 비트는 입력의 교차점에 표시되는 4 개의 값 중 하나입니다 (입력이 하나뿐이므로 NOT의 경우 2 개).

AND | 0 1     OR | 0 1     XOR | 0 1    NOT | 0 1
----+-----    ---+----     ----+----    ----+----
 0  | 0 0      0 | 0 1       0 | 0 1        | 1 0
 1  | 0 1      1 | 1 1       1 | 1 0

한 가지 예는 정수의 하위 4 비트 만 원하는 경우 15 (이진 1111)와 AND로 연결하면 다음과 같습니다.

    201: 1100 1001
AND  15: 0000 1111
------------------
 IS   9  0000 1001

이 경우 15의 0 비트는 효과적으로 필터 역할을하여 결과의 ​​비트도 0이되도록합니다.

또한, >><< 종종 비트 연산자로 포함되고, 그들은 "변화"를 각각 오른쪽 끝의 롤 당신이에서 0 비트쪽으로 이동하고, 공급하고 있다는 비트를 버리고, 일정한 수의 비트에 의해 왼쪽 값 다른 쪽 끝.

예를 들면 다음과 같습니다.

1001 0101 >> 2 gives 0010 0101
1111 1111 << 4 gives 1111 0000

Python의 왼쪽 시프트는 비트가 삭제되는 고정 너비를 사용하지 않는다는 점에서 특이합니다. 많은 언어가 데이터 유형에 따라 고정 너비를 사용하지만 Python은 단순히 너비를 확장하여 추가 비트를 수용합니다. Python에서 폐기 동작을 얻으려면 and8 비트 값이 4 비트 왼쪽으로 이동하는 것과 같이 비트 단위로 왼쪽 이동을 수행 할 수 있습니다 .

bits8 = (bits8 << 4) & 255

그걸 염두에두고, 비트 연산자의 또 다른 예를 들어 당신이 8 비트 하나에 포장하려는 두 개의 4 비트 값이있는 경우, 당신은 운영자의 세 가지를 모두 사용 (수 있습니다 left-shift, and그리고 or) :

packed_val = ((val1 & 15) << 4) | (val2 & 15)
  • 그만큼 & 15 작업은 두 값 모두 하위 4 비트 만 갖도록합니다.
  • << 4이동 왼쪽 4 비트 시프트 인val1 상단에 8 비트 값 4 비트.
  • |단순히이 두 가지를 함께 결합되어 있습니다.

val17이고 val24 인 경우

                val1            val2
                ====            ====
 & 15 (and)   xxxx-0111       xxxx-0100  & 15
 << 4 (left)  0111-0000           |
                  |               |
                  +-------+-------+
                          |
| (or)                0111-0100

43

일반적인 사용법 :

| 특정 비트를 1로 설정하는 데 사용됩니다.

& 특정 비트를 테스트하거나 지우는 데 사용됩니다.

  • 비트를 설정합니다 (여기서 n은 비트 번호이고 0은 최하위 비트입니다).

    unsigned char a |= (1 << n);

  • 조금 지우기 :

    unsigned char b &= ~(1 << n);

  • 약간 전환 :

    unsigned char c ^= (1 << n);

  • 약간 테스트 :

    unsigned char e = d & (1 << n);

예를 들어 목록의 경우를 살펴보십시오.

x | 2비트의 세트 (1)에 사용되는 x(1)

x & 1비트 0 x이 1인지 0 인지 테스트하는 데 사용됩니다.


38

실제로 사용되는 비트 연산자는 무엇입니까? 몇 가지 예를 고맙게 생각합니다.

비트 연산의 가장 일반적인 용도 중 하나는 16 진수 색상을 구문 분석하는 것입니다.

예를 들어, 다음 은 같은 문자열을 받아들이고 Red, Green 및 Blue 값의 튜플을 반환 하는 Python 함수입니다 #FF09BE.

def hexToRgb(value):
    # Convert string to hexadecimal number (base 16)
    num = (int(value.lstrip("#"), 16))

    # Shift 16 bits to the right, and then binary AND to obtain 8 bits representing red
    r = ((num >> 16) & 0xFF)

    # Shift 8 bits to the right, and then binary AND to obtain 8 bits representing green
    g = ((num >> 8) & 0xFF)

    # Simply binary AND to obtain 8 bits representing blue
    b = (num & 0xFF)
    return (r, g, b)

나는 이것을 달성하는 더 효율적인 방법이 있다는 것을 알고 있지만 이것이 시프트와 비트 부울 연산을 모두 보여주는 정말 간결한 예라고 생각합니다.


14

질문의 두 번째 부분은 다음과 같습니다.

또한 실제로 비트 연산자는 무엇에 사용됩니까? 몇 가지 예를 고맙게 생각합니다.

부분적으로 만 해결되었습니다. 이것들은 그 문제에 대한 나의 2 센트입니다.

프로그래밍 언어의 비트 연산은 많은 애플리케이션을 다룰 때 기본적인 역할을합니다. 거의 모든 저수준 컴퓨팅은 이러한 종류의 작업을 사용하여 수행되어야합니다.

다음과 같이 두 노드간에 데이터를 전송해야하는 모든 애플리케이션에서 :

  • 컴퓨터 네트워크;

  • 통신 애플리케이션 (휴대폰, 위성 통신 등).

낮은 수준의 통신 계층에서 데이터는 일반적으로 프레임 이라는 이름으로 전송됩니다 . 프레임은 물리적 채널을 통해 전송되는 바이트 문자열입니다. 이 프레임은 일반적으로 실제 데이터와 헤더 라고하는 부분의 일부인 다른 필드 (바이트로 코딩 됨)를 포함합니다. . 헤더는 일반적으로 통신 상태 (예 : 플래그 (비트) 포함), 프레임 카운터, 수정 및 오류 감지 코드 등과 관련된 일부 정보를 인코딩하는 바이트를 포함합니다. 전송 된 데이터를 프레임으로 가져오고 데이터를 보낼 프레임을 사용하려면 확실한 비트 연산이 필요합니다.

일반적으로 이러한 종류의 응용 프로그램을 처리 할 때 API를 사용할 수 있으므로 모든 세부 사항을 다룰 필요가 없습니다. 예를 들어 모든 최신 프로그래밍 언어는 소켓 연결을위한 라이브러리를 제공하므로 실제로 TCP / IP 통신 프레임을 구축 할 필요가 없습니다. 하지만 여러분을 위해 이러한 API를 프로그래밍 한 훌륭한 사람들을 생각해보십시오. 그들은 확실히 프레임 구성을 다루어야했습니다. 모든 종류의 비트 연산을 사용하여 하위 수준에서 상위 수준 통신으로 앞뒤로 이동합니다.

구체적인 예로, 통신 하드웨어에서 직접 캡처 한 원시 데이터가 포함 된 파일을 제공한다고 가정 해보십시오. 이 경우 프레임을 찾기 위해 파일에서 원시 바이트를 읽고 데이터를 비트 단위로 스캔하여 일종의 동기화 단어를 찾아야합니다. 동기화 단어를 식별 한 후 실제 프레임을 가져 와서 필요한 경우 SHIFT (스토리의 시작일 뿐임)하여 전송중인 실제 데이터를 가져와야합니다.

매우 다른 저수준 애플리케이션 제품군은 병렬 및 직렬 포트와 같은 일부 (고전의) 포트를 사용하여 하드웨어를 제어해야하는 경우입니다. 이 포트는 일부 바이트를 설정하여 제어되며 해당 바이트의 각 비트는 해당 포트에 대한 지침 측면에서 특정 의미를 갖습니다 (예 : http://en.wikipedia.org/wiki/Parallel_port 참조 ). 해당 하드웨어로 작업을 수행하는 소프트웨어를 빌드하려면 실행하려는 명령을 포트가 이해하는 바이트로 변환하는 비트 연산이 필요합니다.

예를 들어, 다른 장치를 제어하기 위해 병렬 포트에 연결된 물리적 버튼이있는 경우 소프트 애플리케이션에서 찾을 수있는 코드 줄은 다음과 같습니다.

read = ((read ^ 0x80) >> 4) & 0x0f; 

이것이 기여하기를 바랍니다.


나는 추가 할 것이다 en.wikipedia.org/wiki/Bit_banging 을 또 다른 방법으로 하여 특히 비트 연산이 유용 할 수있는 예로 병렬 및 직렬 포트에 대해 읽는 경우를 살펴 보겠습니다.
Dan

6

이것이 그 두 가지를 명확히하기를 바랍니다.

x | 2

0001 //x
0010 //2

0011 //result = 3

x & 1

0001 //x
0001 //1

0001 //result = 1

4
죄송합니다 ... 심지어 두 이진 모르는 바보로 결국 서쪽에서 가장 빠른 총 ....려고 노력 :(를 수정했습니다.
Amarghosh

1
x & 1효과를 잘 설명하지 않습니다 x & 2.
dansalmo

5

0을 거짓으로, 1을 참으로 생각하십시오. 그런 다음 비트 and (&) 및 or (|)는 값의 모든 비트를 한 번에 수행한다는 점을 제외하면 일반 및 및 또는처럼 작동합니다. 일반적으로 설정할 수있는 30 개의 옵션이있는 경우 (예 : 창에 그리기 스타일) 30 개의 개별 부울 값을 전달하여 각 값을 설정하거나 해제하지 않아도된다면 플래그에 사용되는 것을 볼 수 있습니다. 옵션을 단일 값으로 결합한 다음 &를 사용하여 각 옵션이 설정되었는지 확인합니다. 이 스타일의 플래그 전달은 OpenGL에서 많이 사용됩니다. 각 비트는 별도의 플래그이기 때문에 2의 거듭 제곱 (일명 비트 세트 만있는 숫자) 1 (2 ^ 0) 2 (2 ^ 1) 4 (2 ^ 2) 8 (2 ^ 3) 2의 거듭 제곱은 플래그가 켜져있는 경우 설정되는 비트를 알려줍니다.

또한 2 = 10이므로 x | 2는 111 (7)이 아니라 110 (6)입니다. 비트가 겹치지 않는 경우 (이 경우 참) | 덧셈처럼 작동합니다.


5

위에서 언급 한 것을 보지 못했지만 산술 연산을 위해 왼쪽 및 오른쪽 시프트를 사용하는 사람들도 있습니다. x로 왼쪽 시프트는 2 ^ x (오버플로하지 않는 한)를 곱하는 것과 같고 오른쪽 시프트는 2 ^ x로 나누는 것과 같습니다.

최근에 나는 그들이 단지 영리 해 지려고 노력하고 있는지 아니면 일반 연산자에 비해 뚜렷한 이점이 있는지는 확실하지 않지만 x << 1 및 x >> 1을 사용하는 사람들을 보았습니다.


1
나는 파이썬에 대해 잘 모르지만 C 또는 더 낮은 어셈블리와 같은 하위 수준의 언어에서는 비트 시프트가 훨씬 더 효율적입니다. 차이점을 확인하려면 각 방식으로이 작업을 수행하는 C로 프로그램을 작성하고 어셈블리 코드로 컴파일 할 수 있습니다 (또는 어셈블리 lang을 알고 있다면 이미 알고있을 것입니다 :)). 명령어 수의 차이를 확인하세요.
0xc0de

2
비트 시프트 연산자 사용에 대한 나의 주장은 대부분의 현대 컴파일러가 이미 산술 연산을 최적화하고 있으므로 영리함이 기껏해야 컴파일러와 싸우고 있다는 것입니다. 나는 C, 컴파일러 또는 CPU 디자인에 대한 전문 지식이 없으므로 내가 옳다고 생각하지 않습니다. :)
P. Stallworth

이것은 더 높아야합니다. 나는 비트 연산자를 정확히 그런 식으로 사용하는 일부 코드를 처리해야했으며 그 대답은 문제를 파악하는 데 도움이되었습니다.
Philippe Oger 2018

4

세트

집합은 수학 연산을 사용하여 결합 할 수 있습니다.

  • 공용체 연산자 |는 두 세트를 결합하여 둘 중 하나에 항목을 포함하는 새 세트를 형성합니다.
  • 교차 연산자 &는 둘 다 항목 만 가져옵니다.
  • 차이 연산자 -는 두 번째가 아닌 첫 번째 세트의 항목을 가져옵니다.
  • 대칭 차이 연산자 ^는 두 세트 중 하나의 항목 만 가져옵니다.

직접 시도 :

first = {1, 2, 3, 4, 5, 6}
second = {4, 5, 6, 7, 8, 9}

print(first | second)

print(first & second)

print(first - second)

print(second - first)

print(first ^ second)

결과:

{1, 2, 3, 4, 5, 6, 7, 8, 9}

{4, 5, 6}

{1, 2, 3}

{8, 9, 7}

{1, 2, 3, 7, 8, 9}

이 답변은 질문과 완전히 관련이 없으며 다른 곳에서 복사하여 붙여 넣은 것 같습니다.
doctaphred apr

질문은 "실제로 비트 연산자가 사용되는 것은 무엇입니까?"라는 질문입니다. 이 답변은 잘 알려지지 않았지만 비트 연산자의 매우 유용한 사용법을 제공합니다.
태경 19

3

이 예는 4 개의 2 비트 값 모두에 대한 작업을 보여줍니다.

10 | 12

1010 #decimal 10
1100 #decimal 12

1110 #result = 14

10 & 12

1010 #decimal 10
1100 #decimal 12

1000 #result = 8

다음은 사용 예입니다.

x = raw_input('Enter a number:')
print 'x is %s.' % ('even', 'odd')[x&1]

2

또 다른 일반적인 사용 사례는 파일 권한 조작 / 테스트입니다. Python stat 모듈 : http://docs.python.org/library/stat.html을 참조하십시오 .

예를 들어 파일의 사용 권한을 원하는 사용 권한 집합과 비교하려면 다음과 같이 할 수 있습니다.

import os
import stat

#Get the actual mode of a file
mode = os.stat('file.txt').st_mode

#File should be a regular file, readable and writable by its owner
#Each permission value has a single 'on' bit.  Use bitwise or to combine 
#them.
desired_mode = stat.S_IFREG|stat.S_IRUSR|stat.S_IWUSR

#check for exact match:
mode == desired_mode
#check for at least one bit matching:
bool(mode & desired_mode)
#check for at least one bit 'on' in one, and not in the other:
bool(mode ^ desired_mode)
#check that all bits from desired_mode are set in mode, but I don't care about 
# other bits.
not bool((mode^desired_mode)&desired_mode)

진실이나 거짓에만 관심이 있기 때문에 결과를 부울로 캐스트하지만 각각에 대해 bin () 값을 출력하는 것은 가치있는 연습이 될 것입니다.


1
마지막 예에서 틀 렸습니다. 다음과 같이 표시되어야합니다 not bool((mode ^ desired_mode) & 0777).. 또는 (이해하기 쉬움) : not (mode & 0777) ^ desired_mode == 0. AND는 흥미로운 비트 만 남기고 XOR은 원하는 모든 비트가 설정되었는지 확인합니다. 명시 적 == 0비교는bool() 있습니다.
Vadim Fint

나는 이것이 파일 작업에만 국한되지 않는다고 생각합니다. 예를 들어, PyQt에서 setWindowFlags. 예 : setWindowFlags(SplashScreen | WindowStaysOnTopHint). 나는 이것이 당신이 '켜기'로 설정하는 토글처럼 보이기 때문에 여전히 혼란 스럽습니다. 그래서 그런 경우에는 '그리고'가 더 직관적으로 보입니다.
eric

2

정수의 비트 표현은 종종 과학 컴퓨팅에서 참-거짓 정보의 배열을 나타내는 데 사용됩니다. 비트 연산이 부울 배열을 반복하는 것보다 훨씬 빠르기 때문입니다. (고급 언어는 비트 배열이라는 개념을 사용할 수 있습니다.)

이것에 대한 훌륭하고 매우 간단한 예는 Nim 게임에 대한 일반적인 솔루션입니다. Wikipedia 페이지 에서 Python 코드를 살펴보십시오 . 비트 배타적 또는 .^


1

배열 요소가 두 값 사이에있는 위치를 찾는 더 좋은 방법이있을 수 있지만이 예제에서 볼 수 있듯이 & 는 여기서 작동하지만 그렇지 않습니다.

import numpy as np
a=np.array([1.2, 2.3, 3.4])
np.where((a>2) and (a<3))      
#Result: Value Error
np.where((a>2) & (a<3))
#Result: (array([1]),)

1

나는 그것을 언급하지 않았다.이 예제는 2 비트 값에 대한 (-) 십진수 연산을 보여줄 것입니다 : AB (A에 B가 포함 된 경우에만)

이 연산은 프로그램에서 비트를 나타내는 동사를 보유 할 때 필요합니다. 때로는 비트를 추가해야하고 (위와 같이) 비트를 제거해야 할 때도 있습니다 (동사가 then을 포함하는 경우).

111 #decimal 7
-
100 #decimal 4
--------------
011 #decimal 3

파이썬 : 7 & ~ 4 = 3 (7에서 4를 나타내는 비트 제거)

001 #decimal 1
-
100 #decimal 4
--------------
001 #decimal 1

with python : 1 & ~ 4 = 1 (1에서 4를 나타내는 비트 제거-이 경우 1은 '포함'4가 아님) ..


0

정수 비트를 조작하는 것이 유용하지만, 비트까지 지정 될 수있는 네트워크 프로토콜의 경우 종종 더 긴 바이트 시퀀스 (하나의 정수로 쉽게 변환되지 않음)를 조작해야 할 수 있습니다. 이 경우는 사용하는 데 유용 비트 스트링 데이터를 비트 연산을 가능하게 라이브러리 - 예를 들어, 하나는 (또는 다른 비트 연산을 수행) 문자열로 또는 16 진수 비트 변화로 문자열 'ABCDEFGHIJKLMNOPQ'을 가져올 수 있습니다 :

>>> import bitstring
>>> bitstring.BitArray(bytes='ABCDEFGHIJKLMNOPQ') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
>>> bitstring.BitArray(hex='0x4142434445464748494a4b4c4d4e4f5051') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')

0

다음 비트 연산자 : & , | , ^~논리 게이트 가 신호에 영향을 미치는 것과 동일한 방식으로 값 (입력에 따라)을 반환합니다 . 이를 사용하여 회로를 에뮬레이트 할 수 있습니다.


0

비트를 뒤집으려면 (즉, 1의 보수 / 반전) 다음을 수행 할 수 있습니다.

값이 모두 1로 ExORed되면 반전이 발생하므로 주어진 비트 폭에 대해 ExOR을 사용하여 반전 할 수 있습니다.

In Binary
a=1010 --> this is 0xA or decimal 10
then 
c = 1111 ^ a = 0101 --> this is 0xF or decimal 15
-----------------
In Python
a=10
b=15
c = a ^ b --> 0101
print(bin(c)) # gives '0b101'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.