2의 보수법으로 음수 표현하기

부호있는 정수를 표현하기 위해 사용하는 2의 보수법이 얼마나 자연스럽고 아름다운지 써보려고 한다. 초딩때 프로그래밍을 처음 배울때는 그냥 외웠었는데 중딩때 쯤 이게 얼마나 아름다운 방법인지에 깨달음(ㅎㅎ)이 왔었더랬다. 2의 보수법으로 음수를 표현하는 기계적 방법(즉 알고리즘)은 아래와 같다.

  1. 모든 비트를 뒤집는다. 예를 들어 양수가 00100000 였다면 11011111 (1의 보수)
  2. 여기에 1을 더한다. 예를 들어 11011111였다면 11100000

00100000(32)을 2의 보수법에 따라 음수로 인코딩한 값은 11100000(-32)이다. 대체 왜 이딴 짓을 하는걸까? 이게 뭐가 아름답나? 위의 절차를 잠깐 잊고 다른 방식으로 생각해보자.

정수의 수직선

초딩때 배운 수직선(perpendicular 말고 number line) 개념을 생각해보자. 선분 위에 자연수들이 늘어져있는거. 자연수가 아니라 정수를 나타내려면 0을 가운데에 그리고 왼쪽으로 음수가 나열되고, 오른쪽으로 양수가 나열되는 무한하게 긴 직선(양쪽에 화살표를 그려서 표현한다)을 그렸더랬다.

image1

그런데 컴퓨터는 튜링 머신이 아니라서 메모리가 유한하기 때문에 무한하게 긴 직선 따위는 존재할 수 없다. 즉, 직선의 양 끝을 대충 잘라야 한다. 8비트 정수라면 -128에서 127 지점을 자르고, 16비트 정수라면 -32768에서 32767 지점을 자른다.

인코딩

직선의 양끝을 위와 같이 자른 다음에 직선의 양끝(-128과 127)을 이어붙여서 고리(ring)로 만들자:

image1

이 그림을 보고 0에서 시작해서 시계방향으로 돌면서 이진수 값을 하나씩 매핑하면 2의 보수법을 따르는 인코딩이 완성된다. 이 그림을 떠올리면 127 다음에 -128이 나오는 이유, 0은 00000000인데 -1은 11111111인 이유, 2의 보수법 인코딩에서 사칙연산이 자연스럽게 수행되는 이유, carry flag가 어떤 경우에 켜지며 그 때의 값이 어떻게 되는지 등 온갖 것들이 자연스럽게 이해된다. 참말 아름답지 아니한가?

Ref1