Apple/Swift

[Swift] 비트 연산과 비트마스킹 (NOT, AND, OR, XOR, 시프트 등)

어멘드 2022. 1. 17. 19:06
반응형

 오늘도 PS를 위한 문법, 비트 연산자이다. 비트 연산은 거의 비트마스킹에 쓰기 때문에 비트마스킹에 활용하는 방법까지 엮어서!

 


Bitwise Operators

 

NOT ( ~ )

 모든 비트를 반대로 뒤집어버린다. 0은 1로 만들고, 반대로 1은 0으로 만든다. 연산자는 ~이다.

let A: UInt8 = 0b00110011   // 0011 0011
let notA = ~A               // 1100 1100

 

AND ( & )

 둘 다 1인 경우에만 1이고, 나머지 경우는 모두 0으로 만든다. 연산자는 &이다.

let A: UInt8 = 0b00110011   // 0011 0011
let B: UInt8 = 0b01010101   // 0101 0101
let AandB = A & B           // 0001 0001

 

OR ( | )

 둘 중에 하나라도 1인 경우에는 1이고, 둘 다 0인 경우에만 0으로 만든다. 연산자는 |이다.

let A: UInt8 = 0b00110011   // 0011 0011
let B: UInt8 = 0b01010101   // 0101 0101
let AorB = A | B            // 0111 0111

 

XOR ( ^ )

 두 비트가 다르면 1, 같으면 0으로 만든다. 연산자는 ^이다.

let A: UInt8 = 0b00110011   // 0011 0011
let B: UInt8 = 0b01010101   // 0101 0101
let AxorB = A ^ B           // 0110 0110

 

Shift ( << ,  >> )

 N칸 만큼 각 모든 비트를 왼쪽 또는 오른쪽으로 민다. 밀고 나서 생긴 빈 비트를 무엇으로 채울지는 자료형이 Signed인지 Unsigned인지에 따라 다르다고 하는데, 비트마스크 용으로 시프트를 공부하고 있기 때문에 Unsigned인 경우만 생각해주자..ㅎㅎ Unsigned는 빈자리를 0으로 채운다. 왼쪽 시프트 연산자는 <<, 오른쪽 시프트 연산자는 >> 이다.

let unsigned: UInt8 = 0b11111111
let shiftRight = unsigned >> 4      // 00001111
left shiftLeft = unsigned << 4      // 11110000

 


Bitmask

 용도는 Int를 [Bool]처럼 사용하는 것이다. N개의 원소에 대해 각각 true/false를 기록해야 하는 상황이다. Int를 이진수로 표현하면 각 비트는 1 아니면 0이므로 이것을 true/false로 사용할 수 있게 된다!

 단, N이 자료형의 크기만큼으로 제한된다. Int32면 32개의 비트로 표현되므로, N=32까지, Int64라면 N=64까지 가능하다. 이렇게 N이 작은 경우에는 [Bool] 대신 쓰면 시간과 메모리 측면에서 효율적이다.

 이제 비트마스킹의 각 연산을 알아보자. 앞으로 언급하는 N번째 원소는 오른쪽에서 N번째 비트이다.

 

N번째 원소를 true(1)로 만들기

 

 N번째 비트에 1을 OR 연산해주면 될 것이다. 나머지는 그대로 두어야 하므로 N번째 비트만 1인 이진수 1 << (N-1) 과 OR를 해준다.

// 3번째 원소를 1로 만들기
var bitmask: UInt8 = 0b11111011     // 1111 1011
bitmask |= (1 << 2)                 // 1111 1111

 

N번째 원소를 false(0)로 만들기

 N번째 비트에 0을 AND 연산해주면 될 것이다. 나머지는 그대로 두어야 하므로 N번째 비트만 0인 이진수 ~(1 << (N-1))과 AND를 해준다.

// 3번째 원소를 0으로 만들기
var bitmask: UInt8 = 0b00000100     // 0000 0100
bitmask &= ~(1 << 2)                // 0000 0000

 

N번째 원소의 값 확인하기

 N번째 비트에 1을 AND 연산을 한 결과가 0이면 0이고, 1이면 1일 것이다. 나머지가 모두 0이고 N번째 비트만 1인 이진수 1 << (N-1)과 AND를 해주면, 나머지 비트는 모두 결과가 0일 것이기 때문에 1이 나올 수 있는 비트는 N번째 비트밖에 없다. 따라서 결과가 0이면 N번째 비트는 0인 것이고 0이 아니면, N번째 비트는 1인 것이다.

// 4번째, 5번째 원소 확인하기
var bitmask: UInt8 = 0b11110000                     // 1111 0000
let check4thBit = bitmask & (1 << 3) == 0 ? 0 : 1   // 0
let check5thBit = bitmask & (1 << 4) == 0 ? 0 : 1   // 1

 

N번째 원소 토글하기

  N번째 원소 토글은 XOR의 아래와 같은 성질을 이용한다. N번째 비트만 토글하고 싶으면 N번째 비트만 11 << (N-1)과 XOR를 해주면 된다.

1과 XOR 연산을 하면 토글된다.
0 XOR 1 = 1
1 XOR 1 = 0

0과 XOR 연산을 하면 그대로이다.
0 XOR 0 = 0
1 XOR 0 = 1
// 3번째 원소 토글하기
var bitmask: UInt8 = 0b00000000     // 0000 0000
bitmask ^= (1 << 2)                 // 0000 0100

 

반응형