본문 바로가기

IT/Linux

보수 표현(부호 절대값, 1의 보수, 2의 보수, excess -7)

컴퓨터를 포함한 각종 논리회로에서 음수를 표현하는 방법은 다음 4가지가 있다.

  1. 부호 절대값 (Sign-Magnitude)
  2. 1의 보수 (1's Complement)
  3. 2의 보수 (2's Complement)
  4. 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에 대한 내용을 추가