developer tip

비트 연산 및 사용

copycodes 2020. 8. 31. 07:59
반응형

비트 연산 및 사용


이 코드를 고려하십시오.

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 책에서 발췌)에서 왼쪽 시프트는 이해하지만 나머지 두 개는 이해하지 못합니다.

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


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

  • 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

일반적인 사용법 :

| 특정 비트를 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 인지 테스트하는 데 사용됩니다.


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

비트 연산의 가장 일반적인 용도 중 하나는 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)

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


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

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

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

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

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

  • 컴퓨터 네트워크;

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

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

In general, when dealing with that kind of applications, an API is available so you don't have to deal with all those details. For example, all modern programming languages provide libraries for socket connections, so you don't actually need to build the TCP/IP communication frames. But think about the good people that programmed those APIs for you, they had to deal with frame construction for sure; using all kinds of bitwise operations to go back and forth from the low-level to the higher-level communication.

As a concrete example, imagine some one gives you a file that contains raw data that was captured directly by telecommunication hardware. In this case, in order to find the frames, you will need to read the raw bytes in the file and try to find some kind of synchronization words, by scanning the data bit by bit. After identifying the synchronization words, you will need to get the actual frames, and SHIFT them if necessary (and that is just the start of the story) to get the actual data that is being transmitted.

Another very different low level family of application is when you need to control hardware using some (kind of ancient) ports, such as parallel and serial ports. This ports are controlled by setting some bytes, and each bit of that bytes has a specific meaning, in terms of instructions, for that port (see for instance http://en.wikipedia.org/wiki/Parallel_port). If you want to build software that does something with that hardware you will need bitwise operations to translate the instructions you want to execute to the bytes that the port understand.

For example, if you have some physical buttons connected to the parallel port to control some other device, this is a line of code that you can find in the soft application:

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

Hope this contributes.


I hope this clarifies those two:

x | 2

0001 //x
0010 //2

0011 //result = 3

x & 1

0001 //x
0001 //1

0001 //result = 1

Think of 0 as false and 1 as true. Then bitwise and(&) and or(|) work just like regular and and or except they do all of the bits in the value at once. Typically you will see them used for flags if you have 30 options that can be set (say as draw styles on a window) you don't want to have to pass in 30 separate boolean values to set or unset each one so you use | to combine options into a single value and then you use & to check if each option is set. This style of flag passing is heavily used by OpenGL. Since each bit is a separate flag you get flag values on powers of two(aka numbers that have only one bit set) 1(2^0) 2(2^1) 4(2^2) 8(2^3) the power of two tells you which bit is set if the flag is on.

Also note 2 = 10 so x|2 is 110(6) not 111(7) If none of the bits overlap(which is true in this case) | acts like addition.


I didn't see it mentioned above but you will also see some people use left and right shift for arithmetic operations. A left shift by x is equivalent to multiplying by 2^x (as long as it doesn't overflow) and a right shift is equivalent to dividing by 2^x.

Recently I've seen people using x << 1 and x >> 1 for doubling and halving, although I'm not sure if they are just trying to be clever or if there really is a distinct advantage over the normal operators.


This example will show you the operations for all four 2 bit values:

10 | 12

1010 #decimal 10
1100 #decimal 12

1110 #result = 14

10 & 12

1010 #decimal 10
1100 #decimal 12

1000 #result = 8

Here is one example of usage:

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

Sets

Sets can be combined using mathematical operations.

  • The union operator | combines two sets to form a new one containing items in either.
  • The intersection operator & gets items only in both.
  • The difference operator - gets items in the first set but not in the second.
  • The symmetric difference operator ^ gets items in either set, but not both.

Try It Yourself:

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)

Result:

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

{4, 5, 6}

{1, 2, 3}

{8, 9, 7}

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

Another common use-case is manipulating/testing file permissions. See the Python stat module: http://docs.python.org/library/stat.html.

For example, to compare a file's permissions to a desired permission set, you could do something like:

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)

I cast the results as booleans, because I only care about the truth or falsehood, but it would be a worthwhile exercise to print out the bin() values for each one.


Bit representations of integers are often used in scientific computing to represent arrays of true-false information because a bitwise operation is much faster than iterating through an array of booleans. (Higher level languages may use the idea of a bit array.)

A nice and fairly simple example of this is the general solution to the game of Nim. Take a look at the Python code on the Wikipedia page. It makes heavy use of bitwise exclusive or, ^.


There may be a better way to find where an array element is between two values, but as this example shows, the & works here, whereas and does not.

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]),)

i didnt see it mentioned, This example will show you the (-) decimal operation for 2 bit values: A-B (only if A contains B)

this operation is needed when we hold an verb in our program that represent bits. sometimes we need to add bits (like above) and sometimes we need to remove bits (if the verb contains then)

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

with python: 7 & ~4 = 3 (remove from 7 the bits that represent 4)

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

with python: 1 & ~4 = 1 (remove from 1 the bits that represent 4 - in this case 1 is not 'contains' 4)..


Whilst manipulating bits of an integer is useful, often for network protocols, which may be specified down to the bit, one can require manipulation of longer byte sequences (which aren't easily converted into one integer). In this case it is useful to employ the bitstring library which allows for bitwise operations on data - e.g. one can import the string 'ABCDEFGHIJKLMNOPQ' as a string or as hex and bit shift it (or perform other bitwise operations):

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

the following bitwise operators: &, |, ^, and ~ return values (based on their input) in the same way logic gates affect signals. You could use them to emulate circuits.


To flip bits (i.e. 1's complement/invert) you can do the following:

Since value ExORed with all 1s results into inversion, for a given bit width you can use ExOR to invert them.

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'

참고URL : https://stackoverflow.com/questions/1746613/bitwise-operation-and-usage

반응형