프로그래밍/수학

컴퓨터가 2의 보수 표현을 사용하는 이유

Lou Park 2022. 2. 4. 00:55

# 컴퓨터의 연산장치가 사칙연산을 하는 법

- 덧셈 , 곱셈: 주어진 데이터 표현을 덧셈 or 시프트 연산

- 뺄셈, 나눗셈: 주어진 데이터 표현에 대한 보수(Complement)를 취하여 덧셈, 시프트 연산

 

컴퓨터는 데이터를 워드(Word)단위로 처리하는데, 운영체제에서 32bit, 64bit로 나누는 것을 보았을 것이다.

이는 바로 워드 사이즈를 가리킨다.

 

워드의 최상위 비트는 부호비트가된다. 부호비트가 0 = 양수, 1 = 음수다.

나머지 비트들은 데이터 값을 표현하는데 사용한다.

 

아래는 1워드가 8bit일때를 기준으로 십진수 -53을 비트로 나타낸 것이다.

 

최상위비트             최하위비트
부호비트 데이터 비트
1 0 1 1 0 1 0 1

 

 

# 왜 컴퓨터는 부호화-2의 보수표현을 사용할까?

1워드를 4bit로 잡고 십진수 +0과 -0을 부호화-절대값, 부호화-1의보수, 부호화-2의 보수로 각각 나타내어보았다.

양수의 경우에는 모든 표현이 같지만, 음수일 경우는 다르다.

 

부호화-1의 보수의 경우, 데이터 비트에 모두 1의 보수를 취한다. (bit를 반전)

부호화-2의 보수의 경우, 부호화-1의 보수에 + 1을 한다. 

 

주어진 워드 비트 수를 초과하는 것을 Overflow라고 하는데,  부호화-1의 보수표현법에서는 초과된 비트를 다시 더해주고, 부호화-2의 보수 표현법에서는 초과된 비트를 무시한다. 

따라서 0의 부호화 2의보수가 1111 + 0001 = 10000 -> 0000이 된다.

 

표현 + 0  - 0
부호화 절대값 0000 1000
부호화 1의 보수 0000 1111
부호화 2의 보수 0000 0000

 

0은 중립값임에도 불구하고, 부호화 2의 보수를 제외한 방식은 표현법이 다르다. 

이렇게되면 연산에서 0의 두가지 표현법을 모두 고려해야하기에 연산이 복잡해진다. 

그래서 컴퓨터에서는 부호화-2의 보수 표현을 이용해 연산한다.

 

-3 + -4를 부호화-2의 보수 표현으로 연산해보자. (4bit)

1) 부호화-절대값 표현에서 2의 보수로 두 수의 표현 바꾸기,

-3 = 1011 → 1100 → 1101 

-4 = 1100 → 1011 → 1100

2) 1101 + 1100 = 11001

3) Overflow가 되었으므로 최상위 비트 1을 무시, = 1001

4) 1001을 2의 보수로 다시변환, 1001 → 1110 + 1 → 1111

5) 1111을 10진수로 변환하면 -7

 

어? 그럼... -7 + -1도 2의 보수로 연산해볼까?

1) -7 = 1111 → 1000 → 1001

-1 = 1001 → 1110 → 1111

2) 1001 + 1111 = 11000

3) 1000

4) 1000 → 1111 + 1 → 10000 → 0000

5) 0...?

 

잘못된게 아닐까? 그럼... +7 + 1을 2의 보수로 연산해볼까?

1) +7 = 0111, 1 = 0001

2) 0111 + 0001 = 1000

3) 1000 → 1111 + 1 → 10000 → 0000

4) 0...?!?!

 

그렇다. +8 과 -8의 표현이 0000으로 같다. 무언가 잘못되었다. 0000은 뭘까?

0000의 정체를 알아보기 위해 0000에 7을 더해보겠다.

1) 0000 + 0111 = 0111

2) 0111 → 0000 + 1 → 0001

3) 10진수로 변환하면 1, 따라서 0000은 사실 -8을 표현한다.

 

워드 사이즈가 4bit 일때 8은 2의보수 표현법으로 표현될 수 없다. 

따라서 4bit로는 -8 ~ 7까지의 표현이 가능하다. 일반화 시키면 다음과 같다.

일반적인 CPU에서 작동하기 위해 대부분의 프로그래밍 언어는 정수형(integer)은 32bit로 표현되는데, 부호가 있는(signed) 정수의 경우 부호비트로 1bit를 써야하므로 2의 31승 - 12,147,483,647을 최대값으로 가진다. 

 

프로그래밍을 처음 배울때, 이것저것 계산하다가 오버플로우나서 -2,147,483,648 이라는 숫자를 자주 접해봤을 것이다. 나도 저 숫자를 꽤나 많이봤고, 볼때마다 "아...뭔가 잘못됬구나" 싶었다. ㅋㅋㅋ 이를 넘어선 숫자의 연산은 다음과 같다. 

-2,147,483,648 - 500 = 2,147,483,148이 된다.  Overflow되어 부호가 사라지고 그상태에서 뺄셈이 진행된다.

+2,147,483,647 + 500 = -2,147,483,149이다. 가장 작은값인 -2,147,483,648을 만드는데 1을 쓰고, 나머지 499가 더해진다.

 

# 그 밖의 재미있는 사실들

1) Y2K38

UNIX 타임 스탬프는 1970년 1월 1일 자정을 1초로 지금까지 초를 세고있는데...이걸 정수형으로 사용했을 경우 2038년 1월 19일 UTC 03:14:07에 -2147483648로 음수 시간이 되어버릴 위험을 안고있다고 한다. (물론, 워킹하는 시스템이라면 시간도 충분히 남았으니 조치를 취할 수 있는 시간이 많이 남긴 했다.) 이를 <2038년 문제(Unix Millennium bug, Y2K38)>라고 부른다. 이런 역사적인  날이 내 생일이라니..! 2038년까지 개발자 일 하고있었으면 좋겠다. ㅋㅋㅋ

 

64bit 정수형의 최대값은 2의 63승 - 1로, 9,223,372,036,854,775,807인데....(후덜덜)

이 형식으로 초를 셀 경우 3000억년 뒤까지 문제없다고한다. 그땐 나 가루도 안남아있을듯...

 

2) 싸이 강남스타일 MV 조회수

유튜브 조회수는 부호가 있는 32bit 정수형을 사용하고 있었는데, 따라서 최대값이 2,147,483,647이었다. 유튜브 직원은 강남 스타일 조회수가 2,147,483,647를 넘길 것을 예상하고 2,147,483,647가 되기전 64bit 정수형으로 수정했다고 한다. 한국 뉴스에 보도되기도 했는데...난 처음알았던 사실이다 ㅋㅋ