비트 연산자는 논리 연산자에 비해 많이 쓰이지는 않지만 특정 상황에서 아주 강력한 쓰임새를 가질 수 있다. 일단 논리 연산자와 기호 부분에서 어떻게 다른지 알아보겠다.
기호 / 논리 연산자 / 비트 연산자
AND / && / &
OR / || / |
NOT / ! / ~
비트 연산자에만 존재
XOR / - / ^
left shift / - / <<
right shift / - / >>
11111111 // 1byte(8bit)
위와 같이 8 bit로 이루어진 어떤 변수가 있다고 가정해보자. 그러면, 일반적으로는 총 256개의 값을 표현할 수 있다고 이해한다. 하지만 각 자리의 비트를 하나의 상태로 가정한다면 이는 실제적인 2진법의 값과 상관없이 각 비트마다 1개, 총 8개의 상태를 저장하는 숫자가 된다. 이렇게 생각하는 이유는 비트 연산은 각 비트마다 연산이 들어가기 때문이다.
Bit shift 연산에는 left shift와 right shift가 존재한다. 이는 각각 <<와 >>로 표기하는데 코드로 예시를 들어보면 다음과 같다.
#include <iostream>
int main() {
unsigned int num = 5; // Binary: 00000000 00000000 00000000 00000101
unsigned int leftShifted = num << 1; // Shift left by 1 position
unsigned int num = 20; // Binary: 00000000 00000000 00000000 00010100
unsigned int rightShifted = num >> 1; // Shift right by 1 position
std::cout << "Original number: " << num << std::endl; // Output: 5
std::cout << "After left shift by 1: " << leftShifted << std::endl; // Output: 10
// Binary after shift: 00000000 00000000 00000000 00001010
std::cout << "Original number: " << num << std::endl; // Output: 20
std::cout << "After right shift by 1: " << rightShifted << std::endl; // Output: 10
// Binary after shift: 00000000 00000000 00000000 00001010
return 0;
}
shift 연산은 2의 n승의 수행을 하는데에 있어서 일반적인 사칙연산보다 속도가 훨씬 빠르다고 하니, 2의 n승을 할때 적극적으로 사용해보자. 화살표 방향과 left/right shift의 이름을 묶어서 외우면 <<fmf 를 보고 left shift가 떠오를 것이고 그러면 왼쪽으로 숫자를 밀어서 그 만큼 값이 커진다라는 연상법으로 이해하면 훨씬 좋다!
기본적으로 cpp에서 변수를 선언하면 signed이다. 따라서 unsigned으로 변수를 선언하려면 변수 타입 앞에다가 따로 unsigned라고 붙여주어야 한다.
int x = 100;
unsigned int y = 100;
int로 예시를 들어보자면, int는 4byte이다. 즉, 8*4=>32bit의 자리수까지 표현이 가능한 변수 타입이다. 여기서 unsigned는 0 ~ 2^32 - 1까지의 값을 나타내고, signed는 -2^31 ~ 2^31 - 1 까지의 수를 나타내게 된다. unsigned에는 따로 부호 비트가 없으나 signed에는 제일 왼쪽비트(MSB)를 부호비트로 사용한다. MSB가 0이면 양수, 1이면 음수이다.
MSB가 음수일때 비트 값으로 해당 숫자를 구하는 것은 직관적으로 힘들 수 있다. 예시를 들어보자면 00000001이 1을 뜻한다면 11111111이 -1을 뜻하기 때문이다. 따라서 어떠한 음수에 해당하는 비트값을 구한다면 그 절댓값에 해당되는 양수 비트를 먼저 구한다음에 어떠한 값을 더해햐 0이 나오는지를 추정하는 것이 더 빠른 길이다. 이는 "2의 보수"라는 개념으로 발전하는데, 그 방법을 알면 빠르게 음수 값에 해당되는 비트를 계산할 수 있다.