자바/코틀린 개발을 하면서 가끔 기본 API 구현체들을 보다 보면 비트 연산자가 많이 보이더라고요. 비트 연산 자체는 알지만 활용하는 방법은 잘 모르다 보니 그 부분에 대해 많이 찾아보면서 공부했어요. 그러다가 궁금증이 하나 생겼어요.
왜 2의 보수를 음수 표현에 사용을 하게 되었는가... 다른 방식은 없었던 걸까?
이 궁금증을 해소하기 위해 자료도 찾아보고, 어느 정도 제 추측도 포함해서 정리를 해보았어요. 이제 같이 한번 알아보도록 해요.
1의 보수
2의 보수를 알기 전에 1의 보수에 대해 짚고 넘어갈께요.
정의
이진법에서의 1의 보수는 이진수를 토글(Toggle) 하는 것을 말해요.
토글이 뭐냐구요? 토글은 반전이라고 생각하시면 돼요. 모든 자릿수에 NOT 연산을 사용하는 거죠.
예시
$ 11_2 $ 의 1의 보수는 뭘까요? $ 00_2 $ 이 되겠죠. 모든 자리에 대해 반전을 하면 되니까요.
2의 보수
자 이제 2의 보수에 대해 알아보도록 할게요.
정의
이진법에서 `특정 수`에서 `어떠한 수`를 더했을 때 2의 거듭제곱이 되도록 만드는 `어떠한 수`가 2의 보수입니다.
이때 이 `어떠한 수`는 항상 양수가 되어야 해요. 음수는 허용하지 않습니다!
예시
$11_2$의 2의 보수는 무엇일까요? $11_2$에 `어떠한 수`를 더해서 $100_2$(=$2^2$=4=2의 거듭제곱)을 만드는 `어떠한 수`를 구하면 되겠죠?
$11_2$의 2의 보수는 $01_2$입니다. 어라, 근데 이렇게 보면 1의 보수와 연관된 규칙도 보이는 것 같아요.
그 규칙은 2의 보수는 1의 보수의 값에서 1을 더한 값과 같아요
$11_2$의 1의 보수는 $00_2$이고 여기에 1을 더하면 2의 보수인 $01_2$이 나오게 되네요. 실제로 모든 이진수에 대해 동일하게 일어나는 규칙입니다!
2의 보수를 음수로 사용한 이유
정의를 알아봤으니 여기서 2의 보수를 왜 음수로 사용했는지 알아봅시다.
논리적인 순서대로 정리해 보았어요.
간략 정리
- 이진수는 최상위 비트를 기점으로 개수가 반으로 나뉘네. 그럼 양수/음수의 균형 있는 분배가 가능하겠다.
- 그럼 최상위 비트가 0인 걸 음수로 할까? 1인걸 음수로 할까?
- 여기에 1의 보수를 써볼까? 최상위 비트가 1인 거에 1의 보수를 쓰면 최상위 비트가 0인 수를 모두 표현할 수 있잖아.(반대도 가능)
- 아무래도 최상위 비트가 1인 거에 1의 보수를 쓰고, 음수라고 표현하는 게 맞겠지? 최상위 비트가 0인 것에 1의 보수를 쓰고 음수라고 하면 수를 0부터 표현할 수 없으니까.
- 아 근데 0이 중복돼서 표시되네...(-0, 0)
- 0이 중복되는 문제를 해결할 수 없나..? 1의 보수를 하고 +1을 하면 되겠구나(2의 보수)
- 2의 보수를 취하니까 덧셈 연산 하나로도 음수 계산이 가능하구나. 2의 보수를 통해 음수를 표현하면 되겠다!
상세 정리
최상위 비트를 기점으로 개수가 반으로 나뉘기 때문에 음수/양수의 균형 있는 분배 가능
비트 제한이 걸린 이진수는 항상 최상위 비트를 기점으로 개수가 반으로 나뉘는 것을 알고 계신가요?
만약 2Bit 자료형이 있다고 가정해 봅시다. 이때 나올 수 있는 이진수는 $00_2$, $01_2$, $10_2$, $11_2$ 이렇게 4가지가 나오게 됩니다.
최상위 비트가 1인 이진수는 $10_2$, $11_2$ 의 두 개고, 0인 이진수는 $00_2$, $01_2$ 의 두 개네요.
이렇게 균형 있게 딱 반으로 나눌 수 있게 됩니다.
그럼 최상위 비트가 0 혹은 1인 이진수를 음수라고 생각하면 양수와 음수를 딱 반으로 균형 있게 분배가 가능하겠네요!
1인 최상위 비트에 1의 보수를 쓰면 최상위 비트가 0인 수를 모두 표현가능(반대도 성립)
2Bit 자료형이 있다고 가정해 봅시다. 이때 나올 수 있는 이진수는 $00_2$, $01_2$, $10_2$, $11_2$이겠네요.
최상위 비트가 0인 수에 1의 보수를 취해볼까요?
- $10_2$ > $01_2$
- $11_2$ > $00_2$
어떤가요? 나머지 최상위 비트가 1인 수를 모두 표현가능하죠? 그럼 반대도 성립하는지 볼까요?
- $00_2$ > $11_2$
- $01_2$ > $10_2$
최상위 비트가 0인 값을 음수라고 표현하면 발생하는 문제
자 이제 제대로 된 음수 표현을 한번 해봐야죠. 앞서 해봤던 1의 보수를 이용해서 음수를 표현해 볼 겁니다.
그럼 최상위 비트가 0인 값들을 음수로 표현해 봅시다. 이 값들에 1의 보수를 취해서 -부호를 붙여주기만 하면 됩니다.
- $ 00_2 → 11_2 = -3 $
- $ 01_2 → 10_2 = -2 $
- $ 10_2 = 2 $
- $ 11_2 = 3 $
결과를 보니 뭔가 이상하죠? 네 맞아요 0 이상 1 이하의 값이 전혀 표현되지 않아요. 그렇다는 것은 제대로 된 수를 표현할 수 없다는 것이죠.
그럼 최상위 비트가 1인 값을 음수로 표현해볼까요?
- $00_2 = 0$
- $01_2 = 1$
- $10_2 → 01_2 = -1$
- $11_2 → 00_2 = -0$
이번에는 그대로 제대로 된 수를 표현할 수 있겠네요. 그래도 문제점이 보여요. 0, -0이 같이 등장하죠? 0은 부호에 관계없이 하나만 존재해야 하는데 여기서는 두 번 표현되게 되네요. 이래서는 컴퓨터가 사칙연산을 할 때 복잡해지게 돼요. 경우의 수를 고려해야 하니까요.
0이 중복되는 문제를 2의 보수를 써서 해결하자
1의 보수를 했을 때 -0이 나온다면, 1의 보수를 했을 때 나오는 모든 결과물에 1을 더하면 해결되는 게 아닐까요?
그것이 바로 2의 보수가 되게 되는 것입니다. 앞서 말씀드렸듯 2의 보수는 1의 보수에 +1을 하면 나온다고 말씀드렸었죠? 그래서 2의 보수를 사용하게 된 것입니다.
한번 예시를 살펴보죠.
- $00_2 = 0$
- $01_2 = 1$
- $10_2 → 10_2 = -2$
- $11_2 → 01_2 = -1$
어떤가요? 0, 1, -2, -1으로 수가 잘 표현되죠? 근데 순서가 좀 이상한 것 같지 않아요?
하지만 이게 정상입니다. 2Bit 표현식에서 양수는 1까지가 최대 값이고, 그 이후로 가려면 최솟값으로 가는 게 일반적이잖아요? 그래서 -2로 가는 거예요.
2의 보수를 사용하면 양수, 음수 덧셈연산도 쉽게 가능하다.
컴퓨터가 양수와 음수를 더하려면 어떤 과정을 거쳐야 할까요? 빼기 연산을 사용해야 할까요?
CPU는 뺄셈 연산을 수행할 수 없는 것이 문제입니다. 무조건 덧셈 연산만을 사용해야 하죠.
그런데 2의 보수를 사용할 경우 큰 문제가 없습니다.
그냥 더하면 알아서 결과가 나오거든요.
저희가 십진수로 $1 - 2 = -1$이라는 계산을 하려고 한다고 해봅시다.
이것은 이진수로 $01_2 + 10_2 = 11_2$으로 표현할 수 있습니다.
결괏값이 $11_2$이죠? 이를 2의 보수로 변환하면 $01_2$이고 십진수로는 $-1$입니다.
어때요. 별 다른 과정 없이 그냥 덧셈만으로도 해결이 되죠? 이게 1의 보수의 경우에도 잘 나오기는 하는데, 0과 -0 처리를 해주어야 해서 연산 과정이 조금 복잡해지게 돼요.
마무리
제 나름대로의 검색과 추론을 통해 "왜 2의 보수를 음수표현에 사용하는지"에 대해 정리해 보았습니다.
이게 실무에 얼마나 도움이 될지는 모르지만, 언젠간 도움이 되리라 믿습니다. 알면 알수록 좋은 것이니까요!
여러분들도 잘 정리가 되셨으면 좋겠다는 마음입니다.