Python/Basic programming

파이썬 비트 연산자 (Bitwise Operators)

noodle-dev 2020. 3. 15. 12:30

1. 비트 연산자(Bitwise Operators)

& (Binary AND) : bit 단위로 and연산을 한다.
| (Binary OR) : bit 단위로 or연산을 한다.
^ (Binary XOR) : bit 단위로 xor연산을 한다.
~ (Binary NOT) : bit 단위로 not연산을 한다.(1의 보수)
<< (Binary left Shift) : bit 단위로 왼쪽으로 비트단위 밀기 연산을 한다.
>> (Binary right Shift) : bit 단위로 오른쪽으로 비트단위 밀기 연산을 한다.

  • 비트 단위로 연산을 수행한다.
  • 0은 거짓으로 1은 참으로 연산하여 결과를 1과 0으로 반환한다.
  • "^(xor)"연산은 두개의 값이 다를 때만 참인 연산이다.
  • " ~(not)" 연산은 1의 보수를 구한다. 컴퓨터에서는 뺄셈을 2의 보수를 덧셈하여 처리한다.
  • "<<"는 연산은 왼쪽으로 1비트 밀때마다 두 배씩 늘어난다.
  • ">>" 연산은 오른쪽으로 1비트 밀때마다 1/2씩 줄어든다.
  • n << m : n * 2의 m승
  • n >> m : n / 2의 m승

 

진법의 초기화 및 출력 그리고 변환

  # 진법 초기화
  a = 10
  print(type(a), a)
  a = 0b10
  print(type(a), a)
  a = 0o10
  print(type(a), a)
  a = 0x10
  print(type(a), a)
  print()
  a = 0B10
  print(type(a), a)
  a = 0O10
  print(type(a), a)
  a = 0X10
  print(type(a), a)
  print("-"*20)

  # 출력
  i = 0x100
  print("i = ", i)
  print("i = ", bin(i))
  print("i = ", int(i))
  print("i = ", oct(i))
  print("i = ", hex(i))
  print("-"*20)

  # 문자열을 형변환
  i = "111"
  print("i = ", int(i))
  print("i = ", int(i, 2))
  print("i = ", int(i, 8))
  print("i = ", int(i, 16))
  print("i = ", int(i, 5))
  print("-"*20)

실행 결과

  <class 'int'> 10
  <class 'int'> 2
  <class 'int'> 8
  <class 'int'> 16

  <class 'int'> 2
  <class 'int'> 8
  <class 'int'> 16
  --------------------
  i =  256
  i =  0b100000000
  i =  256
  i =  0o400
  i =  0x100
  --------------------
  i =  111
  i =  7
  i =  73
  i =  273
  i =  31
  --------------------

 

기본 연산

  # 비트 연산자(Bitwise Operators)
  a = 0b10101010
  b = 0b01110011

  print('a = ',  a, ":", bin(a))
  print('b = ',  b, ":", bin(b))
  print('a & b = ',  a & b, ":", bin(a & b))
  print('a | b = ',  a | b, ":", bin(a | b))
  print('a ^ b = ',  a ^ b, ":", bin(a ^ b))
  print('~a = ',  ~a, ":", bin(~a))

  a = 0b1
  print('a = ', a)
  a = a << 1    # * 2
  print('a = ', a)
  a = a << 1    # * 2
  print('a = ', a)
  a = a << 3    # * 2**3
  print('a = ', a)

  a = a >> 1    # / 2
  print('a = ', a)
  a = a >> 1    # / 2
  print('a = ', a)
  a = a >> 2    # / 2**2
  print('a = ', a)

실행 결과

  a =  170 : 0b10101010
  b =  115 : 0b1110011
  a & b =  34 : 0b100010
  a | b =  251 : 0b11111011
  a ^ b =  217 : 0b11011001
  ~a =  -171 : -0b10101011
  a =  1
  a =  2
  a =  4
  a =  32
  a =  16
  a =  8
  a =  2

 

2. 비트 연산자(Bitwise Operators) 활용

2의 누승 출력하기

  # 비트 연산자(Bitwise Operators)
  # 2의 누승 출력하기
  a = 1
  for i in range(0, 11):
      print('{0:6,}'.format(a << i), end=' ')
  print()

  a = 2
  for i in range(0, 11):
      print('{0:6,}'.format(a ** i), end=' ')
  print()

  a = 1024
  for i in range(0, 11):
      print('{0:6,}'.format(a >> i), end=' ')
  print()

  a = 2
  for i in range(10, -1, -1):
      print('{0:6,}'.format(a ** i), end=' ')
  print()

실행 결과

       1      2      4      8     16     32     64    128    256    512  1,024 
       1      2      4      8     16     32     64    128    256    512  1,024 
   1,024    512    256    128     64     32     16      8      4      2      1 
   1,024    512    256    128     64     32     16      8      4      2      1 

 

보수를 이용한 밸셈

  # 2의 보수를 이용한 뺄셈
  # ~(1의보수) + 1 = 2의 보수
  a = 10
  b = 3
  c = a - b
  d = a + (~b + 1)
  print('a - b = ', c)
  print('a + (~b + 1) = ', d)

실행 결과

  a - b =  7
  a + (~b + 1) =  7

 

두개의 숫자를 교환하기

  # 두개의 숫자를 교환하기
  a = 100
  b = 200
  print('a={0}, b={1}'.format(a,b))

  # 임시 변수를 사용하는 방법
  temp = a
  a = b
  b = temp
  print('a={0}, b={1}'.format(a,b))

  # Python의 tuple을 이용하는 방법
  a, b = b, a
  print('a={0}, b={1}'.format(a,b))

  # ^(xor)연산자를 이용하는 방법
  a = a ^ b
  b = a ^ b
  a = a ^ b
  print('a={0}, b={1}'.format(a,b))

실행 결과

  a=100, b=200
  a=200, b=100
  a=100, b=200
  a=200, b=100

 

10진수를 입력받아 16진수로 출력하기

  # 10진수를 입력받아 16진수로 출력하기
  while True:
      n = int(input('정수입력(1~255사이, 0은종료)'))
      if not n:
          break
      if n<0 or n>255:  # 0x00 ~ 0xFF 사이의 숫자
          print('올바른 범위의 정수를 입력하시오')
          continue
      high = n >> 4 & 0XF     # 상위 4비트만 뽑아내기
      low = n & 0XF           # 하위 4비트만 뽑아내기
      print('원본 : ', bin(n))
      print('8비트중 상위 4비트 : ', bin(high))
      print('8비트중 하위 4비트 : ', bin(low))
      print('사용자 : 0X{0:1}'.format(high if high < 10 else chr(ord('A') + high-10)), end='')
      print('{0:1}'.format(low if low < 10 else chr(ord('A') + low-10)))
      print('파이선 : {}'.format(hex(n)))

실행 결과

  정수입력(1~255사이, 0은종료)255
  원본 :  0b11111111
  8비트중 상위 4비트 :  0b1111
  8비트중 하위 4비트 :  0b1111
  사용자 : 0XFF
  파이선 : 0xff
  정수입력(1~255사이, 0은종료)128
  원본 :  0b10000000
  8비트중 상위 4비트 :  0b1000
  8비트중 하위 4비트 :  0b0
  사용자 : 0X80
  파이선 : 0x80
  정수입력(1~255사이, 0은종료)78
  원본 :  0b1001110
  8비트중 상위 4비트 :  0b100
  8비트중 하위 4비트 :  0b1110
  사용자 : 0X4E
  파이선 : 0x4e
  정수입력(1~255사이, 0은종료)0

 

10진수를 입력받아 2진수 출력하기

  # 10진수를 입력받아 2진수로 출력하기
  while True:
      n = int(input('정수입력(1~255사이, 0은종료)'))
      if not n:
          break
      if n<0 or n>255:  # 0x00 ~ 0xFF 사이의 숫자
          print('올바른 범위의 정수를 입력하시오')
          continue

      mask = 0b10000000  # 8비트 중 상위 1비트만 1인 수 
      print('사용자 : {}을 2진수로 출력하면 0b'.format(n), end='')
      # 8번 반복 
      # 1이 오른쪽으로 1칸씩 이동하며 mask와 and 연산을 수행
      # 지정 위치의 값이 1일때만 같은 수가되고 0이면 0이 된다.
      # 같은때는 1을 다를때는 0을 출력하면 2진수 
      for i in range(0,8):
          print('1' if (mask & n) == mask else '0', end='')
          mask = mask >> 1
      print()
      print('파이썬 : {0}을 2진수로 출력하면 {1}'.format(n, bin(n)))

실행 결과

  정수입력(1~255사이, 0은종료)1
  사용자 : 1을 2진수로 출력하면 0b00000001
  파이썬 : 1을 2진수로 출력하면 0b1
  정수입력(1~255사이, 0은종료)2
  사용자 : 2을 2진수로 출력하면 0b00000010
  파이썬 : 2을 2진수로 출력하면 0b10
  정수입력(1~255사이, 0은종료)3
  사용자 : 3을 2진수로 출력하면 0b00000011
  파이썬 : 3을 2진수로 출력하면 0b11
  정수입력(1~255사이, 0은종료)4
  사용자 : 4을 2진수로 출력하면 0b00000100
  파이썬 : 4을 2진수로 출력하면 0b100
  정수입력(1~255사이, 0은종료)5
  사용자 : 5을 2진수로 출력하면 0b00000101
  파이썬 : 5을 2진수로 출력하면 0b101
  정수입력(1~255사이, 0은종료)6
  사용자 : 6을 2진수로 출력하면 0b00000110
  파이썬 : 6을 2진수로 출력하면 0b110
  정수입력(1~255사이, 0은종료)7
  사용자 : 7을 2진수로 출력하면 0b00000111
  파이썬 : 7을 2진수로 출력하면 0b111
  정수입력(1~255사이, 0은종료)8
  사용자 : 8을 2진수로 출력하면 0b00001000
  파이썬 : 8을 2진수로 출력하면 0b1000
  정수입력(1~255사이, 0은종료)255
  사용자 : 255을 2진수로 출력하면 0b11111111
  파이썬 : 255을 2진수로 출력하면 0b11111111
  정수입력(1~255사이, 0은종료)0

 

색상 값 분리하기/결합하기

색상 값은 어떻게 나타낼까?
  • 대부분 4Byte로 Alpha, Red, Green, Blue를 이용하여 나타냅니다.
  • 2진수 4자리는 16진수 1자리이다. 1Byte는 8Bit이므로 16진수 2자리로 표현 가능한다.
  • and 연산은 값을 지울 때 사용한다.
  • 0으로 &연산하면 0이고 1로 &연산하면 통과이다.
  • or 연산은 값을 설정할 때 사용한다.
  • 0으로 |연산하면 통과이고 1로 |연산하면 1이다.

.

  # 색상분리
  color = 0xAABBCCDD
  alpha = color >> 24 & 0xFF
  red = color >> 16 & 0xFF
  green = color >> 8 & 0xFF
  blue = color & 0xFF

  print(color, hex(color))
  print(alpha, hex(alpha))
  print(red, hex(red))
  print(green, hex(green))
  print(blue, hex(blue))

  # 색상 결합
  color2 = 0
  print(color2, hex(color2))
  color2 = color2 | alpha << 24
  print(color2, hex(color2))
  color2 = color2 | red << 16
  print(color2, hex(color2))
  color2 = color2 | green << 8
  print(color2, hex(color2))
  color2 = color2 | blue
  print(color2, hex(color2))

  # red값 만 삭제
  color2 = color2 & 0xFF00FFFF
  print(color2, hex(color2))

  # red값을 56으로 설정
  color2 = color2 | 0x00560000
  print(color2, hex(color2))

실행 결과

  2864434397 0xaabbccdd
  170 0xaa
  187 0xbb
  204 0xcc
  221 0xdd
  0 0x0
  2852126720 0xaa000000
  2864381952 0xaabb0000
  2864434176 0xaabbcc00
  2864434397 0xaabbccdd
  2852179165 0xaa00ccdd
  2857815261 0xaa56ccdd

 

테트리스 벽돌 출력하기

  # 테트리스 벽돌을 출력해보자
  brick = (0x0660, 0x0F00, 0x2222, 0x6220, 0x4460, 0x4640, 0x7200, 0x6300,0x4620)
  for i in brick:
      mask = 0b1000000000000000
      for j in range(0,16):
          print('■' if (mask & i) == mask else '□', end='')
          if (j+1)%4==0:
              print()
          mask >>= 1
      print()

실행 결과

□□□□
□■■□
□■■□
□□□□

□□□□
■■■■
□□□□
□□□□

□□■□
□□■□
□□■□
□□■□

□■■□
□□■□
□□■□
□□□□

□■□□
□■□□
□■■□
□□□□

□■□□
□■■□
□■□□
□□□□

□■■■
□□■□
□□□□
□□□□

□■■□
□□■■
□□□□
□□□□

□■□□
□■■□
□□■□
□□□□

 

 

 

아직까지 이진수와 16진수 그리고 반복문과 제어문을 모르기 때문에 어려울 것이다. 하지만 많은 응용프로그램에서 자주 사용되는 연산자이다. 숙지하시면 일반 프로그램 보다도 적은 소스로 우수한 성능을 발휘할 수 있는 연산자들이다.

 

 

출처: https://wikidocs.net/20704