3 minute read

음수의 표현

배경

컴퓨터에서 부호가 없는 정수를 표현할 때는 단순히 정수의 절댓값을 2진법으로 변환해서 저장해 사용할 수 있다. 하지만 음수를 표현할때에는 고려해야 할 부분이 더 생기게된다. 컴퓨터에서 음수를 표현하기위해 고안된 방법과 예시를 살펴보자

부호 절댓값법, 1의 보수법, 2의 보수법

음수를 2진수로 나타내는 법은 크게 세가지 방법이 있다. 4비트로 음수를 나타내는 세가지 방법의 예시를 살펴보자.

10진법 부호 절댓값법 1의 보수법 2의 보수법
-8 없음 없음 1000
-7 1111 1000 1001
-6 1110 1001 1010
-5 1101 1010 1011
-4 1100 1011 1100
-3 1011 1100 1101
-2 1010 1101 1110
-1 1001 1110 1111
-0 1000 1111 없음
0 0000 0000 0000
1 0001 0001 0001
2 0010 0010 0010
3 0011 0011 0011
4 0100 0100 0100
5 0101 0101 0101
6 0110 0110 0110
7 0111 0111 0111

부호 절댓값법

부호 절댓값법은 말 그대로 부호를 나타내는 부호비트와, 절댓값을 나타내는 부분으로 나누어 값을 저장하는 방법이다. 최상위비트(MSB)가 1이라면 음수를, 0이라면 양수를 나타내면 최상위 비트를 제외한 부분은 모두 절댓값을 나타낸다.

0b 1111 // 1(-) 111(7) => -7 

사람이 이해하고 다루기 쉽다는 장점이 있으나 -0과 0이 따로 있어 데이터가 하나 낭비되고, 컴퓨터의 입장에서 연산을 할때 부호에 따라 경우를 나누어야 하므로 컴퓨터입장에서는 난해한 방법이라는 단점들이 있다.

1의 보수법

보수

보수란 보충해주는 수로 N진법 수 M에 대한 보수는 M과 어떤수를 더해 N의 제곱수가 되게 보충해주는 어떤수를 지칭하는 말이다.
예를 들어 10진법 수 12에 대한 10의 보수는 더해서 100을 만드는 어떤수를 말하고, 100 - 12을 통해 12의 10의 보수는 88이 됩니다. 또한 n진법에는 n의 보수와 n-1의 보수 두가지가 존재하는데, n-1의 보수는 (n의 보수의 값 - 1)의 값을 지칭하는 말이다. 따라서 12의 9의 보수는 87이고 (100 - 12) - 1이나 (100 - 1) - 12 연산을 통해 구할 수 있고, (9의 보수 + 1) 연산을 통해 10의 보수 또한 구할 수 있다.

2진법에서의 1의 보수

2진법에서 1의 보수는 특별한 의미를 갖는다. 4비트수 1100의 1의 보수를 구하는 예를 살펴보자.

(10000 - 1100) - 1 // 2의 보수 -1
(10000 - 1) - 1100
1111 - 1100 
=> 0011
1100의 1의 보수 => 0011
1100의 비트 반전 => 0011

2진법의 특성상 0과 1만이 존재하므로 2진법에서의 1의보수는 해당 비트의 반전이라는 의미를 갖게 된다.

즉 2진수에서 1의 보수는 비트 반전연산을 통해 구할 수 있고, 2의보수는 (1의 보수 + 1)를 통해 구할 수 있다.

1의 보수법

1의 보수법은 해당 양수의 모든 비트를 반전하여 음수를 표현하는 방법이다.

0110 => 6
1001 => -6
1000 => -7
0111 => 7
0000 => 0
1111 => -0

1의 보수법 덧셈연산

23 + 31
      MSB
    0b 0 000 0000 0000 0000 0000 0000 0001 0111 // 22
    0b 0 000 0000 0000 0000 0000 0000 0001 1111 // 31
  +
_______________________________________________
    0b 0 000 0000 0000 0000 0000 0000 0011 0110 // 53

-23 - 31
      MSB
    0b 1 111 1111 1111 1111 1111 1111 1110 1000 // -23
    0b 1 111 1111 1111 1111 1111 1111 1110 0000 // -31
  +
_______________________________________________
  0b 1 1 111 1111 1111 1111 1111 1111 1100 1000 + 1 (캐리 발생시 +1 처리 해주어야함) // -55 + 1
=>  0b 1 111 1111 1111 1111 1111 1100 1001 // -54 

부호 절대값법 보다 컴퓨터가 이해하기 더 쉽다는 장점이 있으나. 덧셈시 발생하는 캐리에 따라 처리를 고려해야한다는 문제와 0과 -0의 문제는 해결되지 않았다.

2의 보수법

2의 보수법

2의 보수는 양수의 모든 비트를 반전시켜 만든 1의보수에 1을 더해 음수를 표현하는 방법이다. 다시 말해 1의 보수에서 -0인 1111을 -0인 아닌 -1에 매칭하고, 1의 보수에서 -1인 1110을 -2에 매치하는 식으로 한칸씩 미루어 생각하면 된다.

0110 => 6
1001 + 1 -> 1010 => -6
1001 => -7
0110 + 1 -> 0111 => 7

2의 보수법 덧셈연산

-23 - 31
      MSB
    0b 1 111 1111 1111 1111 1111 1111 1110 1001 // -24
    0b 1 111 1111 1111 1111 1111 1111 1110 0001 // -31
  +
_______________________________________________
  0b 1 1 111 1111 1111 1111 1111 1111 1100 1010 // -54 발생한 오버플로우 캐리를 버리기만하면 됨

기존의 +0과 -0 문제를 해결하고, 덧셈 연산을 오버플로우 고려 없이 단순화 시킬 수 있어 컴퓨터의 음수 표현으로 채택된 방법이다.

파이썬에서의 음수

파이썬에서 음수는 별도의 부호필드와 절대값을 저장하고 있다가 비트 연산이 필요할 때에 2의 보수로 변환해 사용한다.

>>> bin(-5)
'-0b101'

파이썬에서 비트를 다룰때 주의할 점은 NOT 연산자인 ~이다. 다음을 살펴보자

>>> int('0b100',2)
4
>>> ~int('0b100',2)
-5

파이썬에서 내부적으로 비트연산은 2의 보수로 변환되어 진행된다. 1의 보수법(비트 반전)에서 ~4를 연산이었다면 -4가 나왔겠지만, 1의 보수법에서 -1만큼 음수를 뒤로 미룬 2의 보수법에선 -4가 아닌 -5가 나오게 된다.
또한 0b 100의 반전으로 0b 011을 기대했을수 있지만 정수자료형은 4바이트(32비트)이므로 사실상 0b 100이 아닌

0b 0000 0000 0000 0000 0000 0000 0000 0100 // 4

이므로 그 반전은 다음과 같다.

0b 1111 1111 1111 1111 1111 1111 1111 1011 // -5

즉 2의 보수법에서 비트반전 ~x 연산은 -x -1의 결과를 나타낸다.

만약 0b 011이 필요하다면 비트마스크를 통해 가능하다.

>>> MASK = 0b 111
>>> 0b 100 ^ MASK
0b 011

Leave a comment