THIS IS ELLIE

스위프트 비트 연산자 본문

개발/Swift

스위프트 비트 연산자

Ellie Kim 2020. 9. 18. 18:25

스위프트에서 비트 연산자를 사용하면 데이터 구조 내에서 각각의 원시 데이터 비트를 조작할 수 있습니다.

그래픽 프로그래밍 및 장치 드라이버 생성과 같은 low-level 프로그래밍에서 더 자주 사용됩니다.

비트 연산자는 인코딩과 디코딩 같은 외부 소스의 원시 데이터와 작업할 때도 유용합니다.

 

NOT 비트 연산자 ~

NOT 비트 연산자는 모든 비트를 반전시킵니다.

let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits  // equals 11110000

위 예제를 살펴보면 0은 1이 되고 1은 0이 되는 것을 확인할 수 있습니다.

 

AND 비트 연산자 &

AND 비트 연산자는 두 수의 비트를 결합합니다.

비트가 1로 동일한 경우에 1을 반환합니다.

let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8  = 0b00111111
let middleFourBits = firstSixBits & lastSixBits  // equals 00111100

두 숫자의 비트가 1과 1이어야 1로 반환되고 0,1이나 1,0, 0,0과 같은 경우는 0으로 반환됩니다.

 

OR 비트 연산자 |

OR 비트 연산자는 두 수의 비트를 비교합니다.

let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits  // equals 11111110

두 숫자의 비트가 1이 1개라도 있으면 1로 설정됩니다.

 

XOR 비트 연산자 ^

두 수의 비트를 비교하며 배타적 OR 연산을 합니다.

let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits  // equals 00010001

두 비트가 동일하면 0이 반환되고 0,1이나 1,0과 같이 같지 않으면 1을 반환합니다.

 

시프트 연산자

시프트 연산자는 왼쪽 및 오른쪽으로 특정 수만큼 모든 비트를 이동시킵니다.

비트 왼쪽 및 오른쪽 시프트는 정수를 2배로 곱하거나 나누는 효과가 있습니다.

왼쪽으로 이동하면 값이 두 배가 되고

오른쪽으로 이동하면 값이 반으로 줄어듭니다.

 

부호 없는 정수에 대한 비트 이동

부호 없는 정수에 대한 비트 이동 순서 (논리적 이동)

비트는 요청된 자리 수만큼 왼쪽 또는 오른쪽으로 이동합니다.

 

정수의 저장 범위를 벗어나는 모든 비트는 버려집니다.

원래 비트가 왼쪽 또는 오른쪽으로 이동한 후 뒤 남겨진 공백에 0이 삽입됩니다.

 

아래 그림에서 왼쪽 그림은 왼쪽으로 이동하는 결과

오른쪽 그림은 오른쪽 이동의 결과를 보여줍니다.

파란색 숫자는 이동되고 회색 숫자는 삭제되고 주황색 숫자는 삽입됩니다. 

 

ex)

4(0100)를 왼쪽으로 시프트 연산 4 << 1 을하면 왼쪽으로 이동해서 값이 두 배가 됩니다.

즉 8(1000)이 됩니다.

4(0100)를 오른쪽으로 시프트 연산 4 >> 1 을하면 오른쪽으로 이동해서 값이 반으로 나뉩니다.

즉 2(0010)가 됩니다.

 

또 아래 예를 통해서 비트 시프팅이 어떻게 이뤄지는지 보겠습니다.

let shiftBits: UInt8 = 4   // 00000100 in binary
shiftBits << 1             // 00001000
shiftBits << 2             // 00010000
shiftBits << 5             // 10000000
shiftBits << 6             // 00000000
shiftBits >> 2             // 00000001

정수만큼 왼쪽, 오른쪽으로 이동되는 비트를 확인할 수 있습니다.

 

비트 시프팅을 사용하여 다른 데이터 타입의 값을 인코딩 및 디코딩할 수 있습니다.

let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16    // redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF           // blueComponent is 0x99, or 153

이 예제에서는 UInt32 상수를 사용하여 분홍색에 대한 CSS 색상 값을 저장합니다.

CSS 색상 #CC6699는 스위프트에서 16진수 표현식인 0xCC6699로 작성됩니다.

Pink와 AND 비트 연산자와  오른쪽 비트 시프트 연산을 활용해 빨간색, 초록색, 파란색 구성 요소로 분해합니다.

 

(색 추출 과정은 16진수를 2진수로 변경하면 쉽게 이해가 될 것 같습니다.)

빨간색은 0xCC6699와 0xFF0000를 AND 비트 연산자를 수행해 얻습니다.

결과로 0xCC0000를 얻고 오른쪽 시프트 연산을 통해 16자리 이동합니다.

0xCC0000는 Ox0000CC로 변경됩니다. 0xCC(10진수로는 204)와 동일합니다.

 

비슷하게 초록색은 0x006600과 0x00FF00를 AND 비트 연산자를 수행해 얻습니다.

결과로 0x006600울 얻고 오른쪽 시프트 연산을 통해 8자리 이동합니다.

그러면 0x66(10진수로는 102)를 얻게 됩니다.

 

마지막으로 파란색은 0xCC6699와 0x0000FF를 AND 비트 연사자를 수행해 얻습니다.

0x000099를 얻게 되고 0x99와 동일하기 때문에 오른쪽으로 이동시킬 필요가 없습니다. 

결과로 0x99(10진수로는 153)를 얻게 됩니다.

 

부호 있는 정수에 대한 이동

부호 있는 정수는 첫 번째 비트(부호 비트)를 사용하여 정수가 양수인지 음수인지를 나타냅니다.

부호 비트는 0이 양수를 의미하고 1이 음수를 의미합니다.

나머지 비트(값 비트)는 실제 값을 저장합니다.

 

부호 비트가 0인 양수는 부호 없는 정수와 똑같은 방식으로 저장됩니다.

부호 비트는 0이라 양수를 나타내고 7개의 나머지 비트는 4를 이진법으로 표현된 숫자들입니다.

 

그러나 음수는 다르게 저장됩니다.

부호 비트는 1이라 음수를 나타내고 7개의 나머지 비트는 124를 이진법으로 표현된 숫자와 같습니다.

이는 128 - 4 = 124이고 결과적으로 -4를 나타냅니다.

이 음수에 대한 인코딩 방식을 2의 보수라고 합니다.

음수를 나타내는 이상한 방법으로 보일 수 있지만 장점이 몇 가지 존재합니다.

 

첫째로 아래와 같이 -1과 -4를 간단하게 더할 수 있습니다.

(부호 비트를 포함) 8비트의 이진수들을 더하고 범위에 벗어나면 버립니다.

둘째로 2의 보수를 사용하면 음수의 비트를 양수처럼 왼쪽과 오른쪽으로 이동할 수 있습니다.

왼쪽으로 이동할 때마다 2배로 늘고 오른쪽으로 이동할 때마다 절반으로 줄어듭니다.

 

오른쪽으로 이동할 때마다 부호 있는 정수를 오른쪽으로 이동할 때와 부호 없는 정수와 동일한 규칙을 적용하되,

왼쪽의 빈 비트를 채우는 것은 0이 아닌 부호 비트로 채웁니다.

이 작업은 부호 있는 정수가 오른쪽으로 이동한 후 동일한 부호를 갖도록 보장합니다. (산술 이동)

 

docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html

반응형

'개발 > Swift' 카테고리의 다른 글

스위프트 배열 크기  (0) 2020.11.09
스위프트 오버플로우 연산  (0) 2020.09.20
dropFirst(_:), removeFirst(_:) 살펴보기  (1) 2020.09.16
스위프트 Identifiable 프로토콜  (0) 2020.06.16
스위프트 클래스  (0) 2020.05.30