• 3.4.1 이진수(Binary numbers)
  • 3.4.2 1의 보수와 2의 보수(Complement)
  • 3.4.3 bitset 표준 헤더(bitset standard header)
  • 3.4.4 비트단위 연산자(Bitwise Operators)

3.4.1 이진수(Binary numbers)

 

개발 관련 지식을 쌓다 보면 반드시 만나는 개념이 바로 이진수이다. 우리가 평소 사용하는 수 체계는 십진수로 이루어져 있지만 컴퓨터는 이진수로 모든 것을 해결한다. 컴퓨터 화면에 보이는 것들은 모두 이진수를 조합해서 보여주는 것이다. 이진수는 모든 자리가 0과 1로만 이루어져 있으며, 모든 자리수는 2의 배수로 나타낼 수 있다.

$$ 337 = 300 + 30 + 7 = 3 \times 10^2 + 3 \times 10^1 + 7 \times 10^0 $$

$$ 0101 1110_{(2)} =  0 \times 2^7 + 1 \times 2^6 + 0 \times 2^5 + 1 \times 2^4 + 1 \times 2^3 + 1 \times 2^2 + 1 \times 2^1 + 0 \times 2^0 $$

 

혹시나 이진수에 대해 다룬적이 없다면 우리 친구 위키피디아를 참고하자. 


3.4.2 1의 보수와 2의 보수(Complement)

 

컴퓨터가 -5를 구하려면 어떻게 구할까? 여기서는 두 가지 방법에 대해 소개할 것이며, 추가적인 내용이 필요한 사람이 있다면 마지막에 참고할 위키피디아를 링크로 남겨두겠다.

 

첫번째로 1의 보수를 사용하는 방법이다.

0000 0101  <- 5를 이진수로 표현
1111 1010  <- 0은 1로 1은 0으로 바꾼다.(1의 보수) 
1111 1011  <- 1을 더한 결과

여기서 1을 더하는 이유는 바로 0과 -0을 구분하지 않기 위함이다. 1의 보수만을 사용한다면 0의 경우 두 개가 존재하게 되며 1을 더했을 때 다시 원래의 수로 돌아오는 효과를 받을 수 있다.

0000 0000  <- 0를 이진수로 표현
1111 1111  <- 0은 1로 1은 0으로 바꾼다.(1의 보수) 
0000 0000  <- 1을 더한 결과(최대 자리를 넘어간 수는 버린다.)

 

두 번째로 2의 보수를 사용하는 방법이다.

1 0000 0000  <- 2의 보수를 사용하기 위한 9자리 이진수(맨 앞 숫자만 1)
0 0000 0101  <- 5에 대한 이진수(위의 숫자에서 이 수를 뺀다.) 
0 1111 1011  <- 뺄셈에 대한 결과

 

1의 보수를 구한 뒤 1을 더하는 연산과 2의 보수를 사용하는 것은 동일한 결과를 얻을 수 있게 된다.

 

추가적으로 더 공부하고 싶다면 2의 보수 위키피디아를 참고하자


3.4.3 bitset 표준 헤더(bitset standard header)

 

이진수를 정수 자료형으로도 다룰 수 있겠지만 메모리에 대한 부담이 크다면 bitset 표준 헤더를 쓰는 것도 하나의 방법이 되겠다. 코딩 문제를 풀거나 이진수 구현에서 어느 정도 서포트를 받고 싶을 때 쓰자! 참고로 컴퓨터는 비트를 다루다 보니 비트단위 연산이 자료형 단위 연산보다 빠르게 계산된다.

#include <iostream>
#include <bitset>

int main()
{
	using namespace std;

	unsigned int a = 1024;
	cout << std::bitset<16>(a) << " " << a << endl;

	unsigned int b = 0b1100;
	unsigned int c = 0b0110;
	cout << b << " " << c << endl;

	return 0;
}

a는 bitset 헤더의 도움을 받아서 작성하였다. 총 16자리로 구성된 이진법이다. 나머지 b와 c는 int 자료형에 이진법으로 담았다. 출력을 한 번 해보자!

 

bitset에 대한 추가적인 정보가 필요하다면 네이버 블로그 링크에 잘 설명되어 있으니 참고해보자!


3.4.4 비트단위 연산자(Bitwise Operators)

 

아래 코드에 주석으로 표현한 것들이 비트단위 연산자의 전부이다.

#include <iostream>
#include <bitset>

int main()
{
	using namespace std;

	// <<	left	shift
	// >>	right	shift
	// ~	not
	// &	and
	// |	or
	// ^	xor

	unsigned int a = 1024;
	cout << std::bitset<16>(a) << " " << a << endl;
	cout << std::bitset<16>(a >> 1) << " " << (a >> 1) << endl;
	cout << std::bitset<16>(a >> 2) << " " << (a >> 2) << endl;
	cout << std::bitset<16>(a >> 3) << " " << (a >> 3) << endl;
	cout << std::bitset<16>(a >> 4) << " " << (a >> 4) << endl;
	cout << std::bitset<16>(~a) << " " << (~a) << endl;
    
	unsigned int b = a << 3;
	cout << std::bitset<16>(b) << " " << b << endl;

	cout << std::bitset<4>(a & b) << endl; // bitwise AND
	cout << std::bitset<4>(a | b) << endl; // bitwise OR
	cout << std::bitset<4>(a ^ b) << endl; // bitwise XOR

	return 0;
}

shift 연산은 방향에 따라 모든 비트를 주어진 숫자만큼 이동시킨다. 최대 자리를 초과한 비트 값은 버리게 된다.

not 연산은 모든 자리를 반전시킨다. 0은 1로 만들고 1은 0으로 만든다. 이전에 다룬 1의 보수와 같은 연산이다.

and 연산은 이항 연산자이며 양 옆의 이진수에 대해서 둘다 1인 비트 단위만 1로 남기고 나머지는 0으로 채운다.

or 연산은 동일한 비트 자리에서 하나라도 1이 있으면 1로 쓰고 둘 다 0이면 0으로 쓴다.

xor 연산은 동일한 비트 자리의 수가 일치하면 0 다르면 1을 주는 연산이다.

+ Recent posts