[CS] 덧셈밖에 못하는 컴퓨터가 어떻게 2의 보수를 이용해 뺄셈을 할까요?
Computer Science

[CS] 덧셈밖에 못하는 컴퓨터가 어떻게 2의 보수를 이용해 뺄셈을 할까요?

Woon2World :: Programming & Art Life

 

우리는 컴퓨터로 사칙연산과 복잡한 미적분까지 계산하지만,

근본적으로 컴퓨터는 덧셈밖에 하지 못 합니다.

멀리까지 가진 말고,

덧셈밖에 못하는 컴퓨터는 어떻게 뺄셈을 하는지 알아봅시다.

 

 

컴퓨터는 2의 보수를 이용하여 음수를 구현합니다.



 

 

뺄셈은 음수를 더하는 것

 

128 - 72는 128 + (-72)로 생각할 수 있죠?

음수의 표현 방법만 어떻게 만들어 낸다면, 뺄셈은 따로 구현할 필요가 없습니다!

컴퓨터는 이미 덧셈을 할 줄 아니까요!

 

그렇다면 어떻게 음수를 표현할 수 있을까요?

수의 범위가 정해져 있다면, 그 범위의 정가운데를 0으로 잡고 그보다 작은 건 음수로 취급하면 될까요?

예를 들어 0~256의 범위가 있을 때에 범위의 정가운데가 128이니, -128만큼 편향해서

0 → -128, 128 → 0, 256 → 128이 되는 겁니다!

하지만 이러면 덧셈의 결과는 -256만큼 편향해야 할 겁니다.

A+B의 덧셈을 할 때 편향을 적용하면 (A-128)+(B-128)이니까요.

애매하죠?

좀 더 좋은 방법이 있을 것 같습니다.

 

2의 보수

 

임의의 수 A에 대해

0 = A - A = A + (-A)입니다.

어떤 수를 원래의 수와 더했을 때 0이 나온다면, 그 수가 바로 원래의 수의 음수입니다.

우리가 이런 걸 유도해볼 수 있을까요?

 

컴퓨터는 이진법을 사용한다는 점을 파고들어봅시다.

모든 비트는 0과 1 둘 중 하나의 값만을 가지고 있죠.

어떤 수를 더해서 모든 비트를 0으로 만드는 방법은 곧잘 떠올리기 쉽지 않지만,

어떤 수를 더해서 모든 비트를 1로 만드는 방법은 비교적 쉽게 떠오릅니다.

바로 모든 비트를 반전시킨 수를 더하는 것입니다.

 

이렇게 어떤 수가 주어지든 모든 비트를 1로 만드는 방법은 알아냈습니다.

그러면, 여기서 0을 만드는 방법은요?

간단합니다. 1을 더하면 됩니다.

단 1만 더하면 모든 자릿수에 자리 올림이 발생하면서 모든 비트가 0으로 바뀌죠.

최상위 비트에서의 자리올림은요?

최상위 비트보다 더 위의 비트는 없기 때문에 버려집니다.

컴퓨터 구조적으로는 Carry 플래그만 활성화되고 말죠.

 

어떤 수와 더해서 0이 되는 수를 만드는 법을 찾는 데 성공했습니다.

그리고 그것을 음수로 취급하기로 했죠?

어떤 수가 있을 때 모든 비트를 반전시킨 후, 1을 더한 것이 그 수의 음수가 됩니다.

 

음수와 양수의 구분

 

그런데, 아직도 애매한 점이 있습니다.

8비트 수 11111111은 255인가요, -1인가요?

(음수일 경우 원래 값의 크기는 다시 1을 뺀 뒤 모든 비트를 반전시켜야 알 수 있겠죠.

11111111은 1을 빼면 11111110이 되고 모든 비트를 반전시키면 00000001이니 그 크기가 1입니다.

8비트 수 11111111은 그 값이 음수라면 -1이었다는 소리죠.)

 

그렇다면 8비트 수 10001000은요? 136인가요, -120인가요?

10001000 + 00000001의 결과는 10001001이긴 한데요, 이것도 137 또는 -119입니다.

어라, 어째 8비트 수가 가질 수 있는 두 가지 값의 절댓값이 n 과 28-n의 세트인 것 같습니다?

어떤 값으로 결정해야 할까요?

편하게 알 수 있는 방법이 있을까요?

 

키는, 어떤 수가 반전된 수냐 하는 것입니다.

반전된 수와 반전되지 않은 수를 구분할 수 있는 방법이 있다면 값을 하나로 결정 가능합니다.

8비트는 28=256개의 수를 표현이 가능하니, 음수 128개와 양수 128개를 표현할 수 있는 것이 합당해보입니다.

128개는 반전된 수고, 나머지 128개는 반전되지 않은 수죠.

어, 그러고보니 8비트 수의 최상위 비트는 단위가 27=128이니까, 최상위 비트가 0인 숫자도 128개, 최상위 비트가 1인 숫자도 128개로 딱 나눠지네요?

수들을 절반으로 딱 나눕니다!

그래서, 어떤 수가 음수인지 양수인지 판정은 이렇게 하도록 합니다.

최상위 비트가 그대로라면 양수, 반전되었다면 음수, 이렇게요.

최상위 비트가 0이면 양수, 1이면 음수가 되는 거죠.

그렇다면 방금 살펴본 11111111과 10001000은 각각 -1과 -120으로 결론이 지어집니다.

이렇게 최상위 비트는 부호 비트(sign bit)라는 특별한 비트가 됩니다.

 

이런 경우도 있습니다.

01000000 + 01000000 = 10000000이죠?

양수끼리 더했는데 부호가 반전되었습니다.

64+64를 했는데 128이 아닌 -128이 나온 겁니다.

이렇게, 음수든 양수든 그 절댓값이 너무 큰 값들을 더하다 보면 올림수가 부호 비트를 침범하는 일들, 부호 비트에서 올림수가 발생하는 일들이 발생하는데요.

이를 산술 오버플로우(arithmetic overflow)라고 부릅니다.

양수와 양수를 더했는데 음수가 나오고, 음수와 음수를 더했는데 양수가 나오는, 비정상적으로 부호가 바뀐 상황을 일컫습니다.

알아두시면 좋겠네요!

 

1의 보수, 2의 보수

 

어라, 어째 8비트 수가 가질 수 있는 두 가지 값의 절댓값이 n 과 28-n의 세트인 것 같습니다?

바로 위 항목에 적힌 문장입니다.

여기서 우리가 사실 어떤 작업을 한 건지 요약이 가능합니다.

8비트 수는 0부터 28-1까지 28개의 수만 표현이 가능합니다.

어떤 수 n과 28-n을 더하면 28이 되어서 표현 가능한 최댓값인 28-1을 넘겨버리죠.

2의 거듭제곱꼴에 해당하는 값들은 최상위 비트만 1인데요, 하필 그 1이 표현 범위를 벗어났으니

표현되는 범위에선 모든 비트가 0이 되는 겁니다.

 

어떤 수와 더해서 kn이 되는 수가 그 수에 대한 k의 보수입니다.

우리는 음수 표현법으로 2의 보수를 채택한 것입니다.

 

수의 음수화 과정 중에 모든 비트를 반전시킨 것이 있었죠?

그렇게 모든 비트를 반전시킨 수를 1의 보수라 합니다.

어떤 수와 더해서 1n이 되는 수라 1의 보수인 것이 아니고요.

영어로 "ones' complement"인데, 이를 직역하면 "1들의 보수"가 됩니다.

사실 1의 보수는 여러 개의 1들로 이루어진 수에 대한 보수라고 해석하는 것이 맞는 거죠.

 

보통 음수 표현법을 설명할 때 "1의 보수를 만든 뒤 1을 더하라, 그러면 그것이 2의 보수이자 음수 표현이다."라고 합니다.

그 말인 즉, 모든 비트를 반전시킨 후 1을 더하라는 말이죠.

우리가 위에서 했던 것이죠?

보수를 쓴다는 사실보다 왜 보수를 쓰게 됐는지가 중요하다고 생각해

위에서는 아예 보수라는 언급 없이 설명을 했습니다.

 

 

유용한 것 한 가지, 쉽게 음수를 만드는 방법이 있는데요.

오른쪽에서부터 세서 처음 1을 만났을 때, 그 왼쪽 비트들을 전부 반전시키는 겁니다.

모든 비트 반전과 1 더하기의 두 가지 절차를 거치는 원래 방법에 비해 좀 더 간편하니,

알아가시기 바랍니다.