C프로그래머가 알아야 할 것들 - 01 진법

C프로그래머가 알아야 할 것들 - 01 진법

왜 진법에 대하여 배워야 하는가?

진법이란, 수를 세는 방법을 의미합니다. 수를 셀 때, 0부터 몇까지 세는지를 의미한다고 생각하시면 됩니다.

우리가 수를 셀 때, 0~9까지 세지요? 이 것을 10진법이라고 부릅니다. 시간에서 분, 초 등을 셀 때 쓰이는 0~59까지 세는 방법을 60진법이라고 합니다. 이와 달리 컴퓨터는 전류가 흐를 때(1)와, 아닐 때(0) 밖에 구분하지 못하기 때문에, 0과 1로써 수를 세는데 이를 2진법이라고 부릅니다.

게임과 메신저, 음악 재생과 같은 것들이 0과 1만으로 된다는 게 말이나 되냐며 못 믿으실 분들도 계실 텐데요, 이 것은 챕터2 비트의 법칙에서 자세히 설명하도록 하겠습니다.

2진법

2진법(Binary)는 0과 1로써 수를 세는 방법입니다. 자리수가 2가 되었을 때 자리 올림을 하여 10으로 표시하는 수 체계죠.

2진수는 표현할 때,

0011(2)

위와 같이 표현 하곤 합니다. 괄호와 그 안에 숫자는 반드시 써야 하는 건 아니고, 혼돈의 여지가 있을 때만 사용 하곤 합니다.

2진수 10진수
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 10

위의 표를 보시면, 대강 어떤지 감이 오실 겁니다. 10진수가 11일 때 2진수로는 몇이 될까요? 네 그렇죠~ 1011이 되는 겁니다. 그런데.. 2진수가 너무 읽기 힘들죠?

8 4 2 1
1 0 0 1 //자릿수가 1일 때마다, 머리 위에 위치한 수만큼 더해줍니다

8에 위치한 2진수가 1이니 8, 4와 2자리에 위치한 수는 0이니 그냥 내버려두고, 1의 자리에 위치한 수가 1이니 1. 그래서 나온 수인 8과 1을 더하면 9가 되는 거죠. 방금 전 방식보단 읽기 쉬워졌죠?

마찬가지로 이진수가 커질 때에도

128 64 32 16   8 4 2 1
0  0  0  0    0 0 0 0

이런 식으로, 수가 하나 증가할 때마다 수가 배로 증가하게 됩니다. 이렇게 하니 2진수 읽는 법은 감이 오죠?

그런데.. 음수를 표현할 땐 어떻게 해야 할까요? -0011

이런 식으로 하면 될 거라고 생각 하신 분 들이 많으실 것 같습니다.

아쉽게도, 컴퓨터 에서 수를 다룰 때는 -부호를 사용할 수 없습니다.

그래서 최상위 비트(MSB: 가장 앞에 있는 비트를 의미)를 부호 비트로 사용하게 되는 것이죠. 비트란 다음 강좌에서 배우게 될 Binary Digit 약자입니다.

최상위 비트가 0이면 양수, 1이면 음수로 표현 하기로 했습니다. 0001은 1, 1001은 -1 이렇게 말이죠.

그런데 이것은 문제가 있습니다. 2진수의 계산이 힘들어진 것이죠.

1001 + 0001 = 1010
(-1)   (1)   (0 이어야 함)

2진수의 덧셈에서 자리 올림수가 발생하면 일반 덧셈에서 자리 올림 수와 마찬가지로 처리해주면 됩니다.

그건 그렇고, 뭔가 이상하죠? 1010이라니…최상위 비트가 1이니 음수인 거 같고, 뒤가 010이니 -2인 것 같은데… 어? 0이 아니네요?

그래서 나온 것이 1의 보수입니다.

1의 보수란, 음수 표현 시에 0을 1로, 1을 영으로 모든 수를 반전 시키는 것이죠.

1의 보수로 표현하자면, 0001은 1, 1110은 -1이 되는 거죠.

자.. 아까 계산이 잘못되었던 -1에서 1을 더해볼까요?

1110 + 0001 = 1111
(-1)   (1)    (0이어야 함)

어? 여전히 뭔가 이상하죠?? 최상위 비트가 1이니 음수인 거 같고.. 111이라면 -7? 왜 또 0이 아니지? 또 문제가 있었습니다. 그래서 2의 보수란 것이 나오게 된 것입니다.

2의 보수란 0을 1로, 1을 0으로 모두 바꿔준 후에 1을 더하는 방법입니다.

0001은 1, 1111은 -1이 되는 것이죠.

그럼 다시.. 계속 잘못 되었던 계산인 -7에서 7을 더해봅시다.

1111 + 0001 = 10000
(-1)   (1)   (0이어야 함)

음.. 이번에도 최상위 비트가 1이군요. 그럼 음순가? 그런데 뒤가 0000이네요? 하지만 이 계산은 맞습니다. 맨 앞에 초과된 1은 무시하기 때문입니다. 그래서 0000 즉 0이 되는 것이죠.

왜 2의 보수가 사용되는지 아셨겠죠?

참고로 1의 보수의 또 다른 문제점은 0이 두 개이기 때문입니다. 1111 1111과, 0000 0000 각각 음수 0 양수 0을 의미합니다.

이에 비해 2의 보수는 0000 0000은 당연히 0이고, 0의 1의 보수인 1111 1111에서 1을 더하면 1 0000 0000이 되고, 이때 초과된 1은 무시하게 되므로 0은 양수 0 하나만 남게 되는 것이죠. 이로써 아까 -1에서 1을 더하는 계산에서의 초과된 1을 무시하는 이유도 함께 이해가 되시죠?

8진법

8진법(Octal)이란 0~7로 수를 세고, 자릿수가 7이 넘어 8이 되었을 때는 자리 올림 하여서, 10으로 표현하는 수 체계입니다.

8진수는 표기할 때,

12(8)

이런 식으로 작은 괄호로 8을 붙여서 표현하곤 하지만, 2진수와 마찬가지로 반드시 표기해줄 필요는 없습니다.

C언어 등의 고급 언어에서 사용시 일반적으로 숫자0을 붙여서 사용하죠.

012

아래 표를 보시면, 2진수, 8진수, 10진수의 관계를 아실 수 있을 겁니다.

2진수 8진수 10진수
0000 0 0
0001 1 1
0010 2 2
0011 3 3
0100 4 4
0101 5 5
0110 6 6
0111 7 7
1000 10 8
1001 11 9
1010 12 10

8진수는 그 자체적인 의미도 중요하지만, 2진수에서의 변환이 매우 편리하다는 장점이 있습니다. 바로 수를 세 개 단위로 묶어서 표현하면 되는 것이죠.

4 2 1
1 1 1 //7입니다

8진수로 바꿀 때는, 4+2+1=7이 되는 거죠.

이런 식으로, 두 자리 수 이상일 때도 마찬가지로,

4 2 1    4 2 1
1 1 0    0 1 1
4+2=6    2+1=3

8진수로 63이 되는 겁니다.

16진법

16진법(Hexadecimal)이란, 수를 0부터 15로 세다가, 16이 되어 자리 올림 시 10으로 표현하는 방법을 말합니다. 그런데…뭔가 조금 이상하죠? 0~15로 수를 센다면, 0~9는 괜찮겠지만, 10부터 15는 자리 올림 된 10~15와 같게 되니까요. 그래서 16진수에서는 0~9는 10진수와 같이 표기하고, 10~15는 A~F로 표현하게 됩니다.

16진수도 8진수 2진수와 마찬가지로,

AF (16)

위와 같이 표기할 수 있습니다.

C언어 등 고급언어에서 16진수 표현할 때 숫자 앞에 0x (숫자 0과 알파벳 x)를 붙여서 사용합니다.

0xAF

아래 표를 보시면 진법에 따른 수 표현 방식을 이해 하실 수 있을 겁니다.

2진수 8진수 10진수 16진수
0000 0 0 0
0001 1 1 1
0010 2 2 2
0011 3 3 3
0100 4 4 4
0101 5 5 5
0110 6 6 6
0111 7 7 7
1000 10 8 8
1001 11 9 9
1010 12 10 A
1000 13 11 B
1001 14 12 C
1010 15 13 D
1010 16 14 E
1010 17 15 F
1010 20 16 10

16진수도 8진수처럼 2진수에서의 변환이 쉽다고 했었죠?

16진수도 2진수를 8진수로 변환하는 것과 비슷합니다. 2진수 4개씩 묶어서 16진수로 변환하면 되는 것이죠.

8 4 2 1
1 1 0 0 //12입니다

8+4=12인데, 12는 알파벳 C로 표현하기로 했으니,

8+4=C로 표현할 수 있는 것이죠.

8 4 2 1    8 4 2 1
1 0 1 0    0 0 1 1
8+2=A      2+1=3

A3으로 4자리씩 묶어서 변환함으로써 2진수를 좀 더 읽기 쉽게 하는 것이죠. 기계어에서 표현하는 수 체계도 16진법이므로 알아두면 여러모로 도움이 되겠죠?

Comments

comments powered by Disqus