컴퓨터를 포함한 각종 논리회로에서 음수를 표현하는 방법은 다음 4가지가 있다.
- 부호 절대값 (Sign-Magnitude)
- 1의 보수 (1's Complement)
- 2의 보수 (2's Complement)
- excess - n
그 외에 양수만 표현하는 unsigned 방식도 있다.
그런데 실제로 널리 사용되는 것은 2의 보수 방식이다. 이유는 회로가 간단해지기 때문이다. 위의 세가지 방식을 각각 살펴보면서 장·단점을 비교해 보자.
1. 부호 절대값 (Sign-Magnitude)
부호 절대값 방식은 가장 쉽게 생각할 수 있는 방식이다. MSB(최상위비트)을 부호비트(0이면 양수, 1이면 음수)로 사용하고, 나머지는 절대값을 표현한다. 4비트 정수를 예로 들면,
0000 +0 1000 -0
0001 1 1001 -1
0010 2 1010 -2
0011 3 1011 -3
0100 4 1100 -4
0101 5 1101 -5
0110 6 1110 -6
0111 7 1111 -7
그런데 부호 절대값 방식에는 몇 가지 문제가 있다. 우선 0이 두 개(+0과 -0)나 존재하기 때문에, 둘 다 0으로 인식하도록 해야 한다. 심각한 문제는 덧셈과 뺄셈을 할 때이다. 인간이 직접 계산할 때처럼 부호와 절대값을 따로 분리해서 계산해야 하고, 음수를 더함으로써 뺄셈을 구현할 수가 없어서 뺄셈기를 따로 구현해야 한다. 그러면 인간이 덧셈과 뺄셈을 수행할 때의 과정을 살펴보자.
2(10) + 3(10) = 0 010 + 0 011 = 0 101 = 5(10)
(양수끼리 더했으므로 양수) <덧셈기 사용>
-2(10) + -3(10) = 1 010 + 1 011 = 1 101 = -5(10)
(음수끼리 더했으므로 음수) <덧셈기 사용>
3(10) - 2(10) = 0 011 - 1 010 = 0 011 = 1(10)(절대값이 큰 수에서 작은 수를 뺐으므로 양수) <뺄셈기 사용>
2(10) - 3(10) = 0 010 - 1 011 = -(011 - 010) = 1 001 = -1(10)
(절대값이 작은 수에서 큰 수를 뺄 경우에는 순서를 바꿔서 빼고 결과는 음수) <뺄셈기 사용>
인간에게는 매우 쉬운 일이지만, 위의 모든 사항을 고려하여 계산을 수행하는 회로를 만드는 것은 쉬운 일이 아니다. 그리고 <, >, <=, >= 등의 비교연산을 수행할 때 다음과 같은 모순이 생긴다.
3(10) > 2(10) = 0011 > 0010 = TRUE
-2(10) > -3(10) = 1010 > 1011 = FALSE (???)
위와 같이 음수의 경우는 반대가 되므로 이를 구분해야 한다. 사실 비교연산은 뺄셈을 한 후 결과의 부호를 가지고 판단하기 때문에 이는 덧셈과 뺄셈 문제와 동일하다.
2. 1의 보수 (1's Complement)
1의 보수 방식은 부호 절대값 방식에서 단순히 음수의 순서를 뒤집은 것이다.
0000 +0 1000 -7
0001 1 1001 -6
0010 2 1010 -5
0011 3 1011 -4
0100 4 1100 -3
0101 5 1101 -2
0110 6 1110 -1
0111 7 1111 -0
음수의 순서를 뒤집기만 한 것이라 별것 아닌것 같지만 사실 엄청난 유리함이 있다. 우선 재미 있는 성질이 하나 생긴다. 비트를 반전시키면 부호가 바뀌게 된다. 다행히 비트반전은 쉽게 구현할 수 있다. 그리고 MSB가 0이면 양수, 1이면 음수라는 성질은 그대로 유지된다.
3(10) = 0011 >> 1100 = -3(10)
-6(10) = 1001 >> 0110 = 6(10)
뿐만 아니라 부호 절대값 방식에서 골치거리였던 것이 깔끔하게 해결된다. 부호와 절대값을 따로 계산하지 않아도 되고, 음수를 더하는 방식으로 뺄셈을 할 수 있게 된다. 단, 캐리가 발생하면 LSB(최하위비트)에 1을 더해줘야 한다.
2(10) + 3(10) = 0010 + 0011 = 0101 = 5(10) <덧셈기 사용>
-2(10) + -3(10) = 1101 + 1100 = 1001 + 0001 = 1010 = -5(10) (캐리 발생) <덧셈기 사용>
3(10) - 2(10) = 0011 + 1101 = 0000 + 0001 = 0001 = 1(10) (캐리 발생) <덧셈기 사용>
2(10) - 3(10) = 0010 + 1100 = 1110 = -1(10) <덧셈기 사용>
어째튼 덧셈과 뺄셈이 매우 간단해졌다. 음수의 비교연산 모순도 해결되었다.
3(10) > 2(10) = 0011 > 0010 = TRUE
-2(10) > -3(10) = 1101 > 1100 = TRUE
그런데 여전히 0이 두 개인 것과 캐리를 처리해야 하는 문제가 남아있다. 즉, 0000과 1111을 둘 다 0으로 처리해야 하고, 계산과정에 캐리가 발생됐는지 감시해서 LSB에 1을 더해주는 회로를 구성해야 한다.
3(10) - 3(10) = 0011 + 1100 = 1111 >> 0000
게다가 위와 같이 실제 계산과정에서 발생하는 0은 항상 -0인 1111이다.
3. 2의 보수 (2's Complement)
2의 보수 방식도 단순해서 그저 눈에 거슬리는 -0을 없애기만 한 것이다.
0000 0 1000 -8
0001 1 1001 -7
0010 2 1010 -6
0011 3 1011 -5
0100 4 1100 -4
0101 5 1101 -3
0110 6 1110 -2
0111 7 1111 -1
-0이 없어지고 대신 -8(10)이 등장한 것 외에는 별것 아닌것 같지만, 1의 보수 방식의 골치꺼리였던 -0 문제와 캐리를 처리해야 하는 문제가 사라진다. 2의 보수 방식에서는 부호를 바꾸려면 비트를 반전한 다음 LSB에 1을 더하면 된다.
3(10) = 0011 >> 1100 + 0001 = 1101 = -3(10)
-6(10) = 1010 >> 0101 + 0001 = 0110 = 6(10)
-0는 아예 없으니 이미 해결됐고, 이제 캐리를 처리하지 않아도 되는지 직접 계산해보자.
2(10) + 3(10) = 0010 + 0011 = 0101 = 5(10)
-2(10) + -3(10) = 1110 + 1101 = 1011 = -5(10) (캐리 발생)
3(10) - 2(10) = 0011 + 1110 = 0001 = 1(10) (캐리 발생)
2(10) - 3(10) = 0010 + 1101 = 1111 = -1(10)
위에서 캐리가 발생했을 때, LSB에 1을 더해주지 않아도 결과가 정확한 것을 확인할 수 있다. 이제 덧셈이든 뺄셈이든 그냥 더하기만 하면 된다. 이제 구현해야 하는 회로가 무척 간단해졌음을 느낄 것이다.
2의 보수 방식의 장점을 요약하면 다음과 같다.
- MSB가 0이면 양수, 1이면 음수라는 성질이 유지된다.
- 음수를 더하는 방식으로 뺄셈을 할 수 있다.
- 음수의 비교연산에서 발생하는 모순이 해결된다.
- 0이 두개나 존재하는 모순이 해결된다.
- 덧셈과 뺄셈을 구현할 때 캐리를 처리하지 않아도 된다.
3. unsigned
이 방식은 크게 설명이 필요없을듯 하다.
예를 들어 4비트 일경우 부호비트를 신경쓰지 않고 2진수를 10진수로 바꿔주면
그것이 unsigned의 값이 된다.
일단 사람 입장에서는 가장 직관적인 표현방식이다.
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 10
1011 11
1100 12
1101 13
1110 14
1111 15
위와 같은 순서다. 더이상 무슨 설명이 필요하랴?
3. excess - 7
대형 컴퓨터에서 많이 사용하는 방식이다.
excess 뒤에 붙는 숫자는 굳이 고정된것이 아니라 연산 가능한 비트수에 따라 달라진다.
위의 2의 보수와 같이 4비트 일때는 7이고 비트수가 올라가면 그 만큼 올라가게 된다.
이 앞의 방식은 앞의 부호비트가 0일때 양수였지만 excess - 7 방식은 부호비트가 0일때
음수를 표현한다.
0000 -7 1000 1
0001 -6 1001 2
0010 -5 1010 3
0011 -4 1011 4
0100 -3 1100 5
0101 -2 1101 6
0110 -1 1110 7
0111 0 1111 8
바로 위와 같이 표현한다.
-7에서 부터 줄어들었다가 다시 8까지 증가한다.
표현 범위는 0이 하나이기 때문에 1의 보수나 2의 보수와 같지만
-8대신 양수 8이 존재한다.
처음에는 복잡하게 느껴질수 있지만 나중에 가면 오히려 계산하기가 편해진다.
계산방법은 단순하다 unsigned에 해당하는 2진수 코드에 7을 빼주기만 하면된다.
여기서 7을 빼는 이유는 excess -7 방식이기 때문이고 당연히 excess -127 방식이면 127을
빼야한다. excess -7이 마이너스 부호를 뜻하는건지 그냥 Dash인지는 모르겠다.
예를들어 0000 일때 unsinged의 값은 0이다. 여기서 7을 빼면 -7이다.
즉 excess -7 방식일때 코드 0000의 값은 -7이다.
excess -7 방식에서 0을 표현하고자 한다면 반대로 0에 7을 더한 unsigned 코드를 만들면 된다.
그 값은 0111이다.
약간 햇갈릴수도 있는데 정리하자면
excess - 7 방식의 코드를 봤는데 그코드를 10진수로 변환해야 한다면 그 코드의 unsigned 값을
계산하고 거기에 -7을 해주면 된다.
어느 정수를 excess -7 방식의 코드로 변환하고자 한다면 그 정수에 7을 더한후 2진수 코드로 변환하면
된다.
이런 excess 방식을 이용하는 컴퓨터 중에서 drop-bit를 사용하는 컴퓨터도 있는데
거기에 대해서는 다음에 설명하겠다.
마지막으로 아래 도표는 위에 나온 모든 방식의 코드 변환표이다.
위의 내용과 함께 보면 아마 이해가 더 빨라질것이다.
Code |
The Represented Number | ||||
4-bit word |
unsigned |
sign - magnitude |
1's complement |
2's complement |
excess -7 |
0000 |
0 |
0 |
0 |
0 |
-7 |
0001 |
1 |
1 |
1 |
1 |
-6 |
0010 |
2 |
2 |
2 |
2 |
-5 |
0011 |
3 |
3 |
3 |
3 |
-4 |
0100 |
4 |
4 |
4 |
4 |
-3 |
0101 |
5 |
5 |
5 |
5 |
-2 |
0110 |
6 |
6 |
6 |
6 |
-1 |
0111 |
7 |
7 |
7 |
7 |
0 |
1000 |
8 |
-0 |
-7 |
-8 |
1 |
1001 |
9 |
-1 |
-6 |
-7 |
2 |
1010 |
10 |
-2 |
-5 |
-6 |
3 |
1011 |
11 |
-3 |
-4 |
-5 |
4 |
1100 |
12 |
-4 |
-3 |
-4 |
5 |
1101 |
13 |
-5 |
-2 |
-3 |
6 |
1110 |
14 |
-6 |
-1 |
-2 |
7 |
1111 |
15 |
-7 |
-0 |
-1 |
8 |
---------------------------------------------------------------------------------------------------
출처 : http://blog.naver.com/dreamincalm/130081559335
정리가 너무 잘되어 있어서 그냥 수정없이 그대로 옮겨옴
2010.5.23 원본에서 excess -7과 unsinged에 대한 내용을 추가
'IT > Linux' 카테고리의 다른 글
페도라12에 삼성 넷북N140 무선랜 RTL8192 드라이버 설치 (0) | 2013.01.11 |
---|---|
한글 putty 다운로드 (0) | 2013.01.11 |
Linux vi편집기 명령어 (0) | 2013.01.11 |
Fedora Core 4 자바 설치하기 (0) | 2013.01.11 |
각종 진법 변환(2진수 실수끼리의 연산, 실수의 진법변환 등) (0) | 2013.01.11 |