2진수의 음수 표현
비트연산자에 대해 배우면서 ~num2(11111111 11111111 11111111 11110000)이 왜 정수 -16이 되는지 의아했다.
이를 이해하기 위해서는 2진수의 음수가 어떻게 표현되는지 알아야 한다.
- 2진수 음수를 나타내는 첫번째 방법 ~ 부호가 있는 절대치를 이용하는 방법.
: 2진수의 가장 왼쪽 비트(MSB)로 양/음수를 나타내고, 나머지 비트로 수를 나타낸다.
가장 왼쪽 비트(MSB)가 0이면 양수, 1이면 음수를 나타낸다.
*MSB(Most Significant Bit): 가장 중요한 비트. 가장 왼쪽 비트가 수에 가장 큰 영향을 주므로 가장 중요한 비트가 된다.
예시)
8자리 2진수로 수를 나타낸다고 가정하자.
10진수 15를 2진수로 나타내면, 00001111 이 된다. MSB가 0이기 때문에 이 수는 양수이다.
MSB | 나머지 | |||||||
비트 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
10진수 -15를 2진수로 나타내면, 10001111 이 된다. MSB가 1이기 때문에 이 수는 음수이다.
MSB | 나머지 | |||||||
비트 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
참 직관적이고 편하지만, 단점이 있다.
컴퓨터는 부호가 있는 절대치로 나타낸 수를 연산하지 못한다. 15와 -15를 계산해보자.
2진수 | 10진수 | ||||||||
0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | (= 15) | |
+ | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | (= -15) |
= | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | (= -30) |
0이 나와야 하는데 엉뚱한 값이 나와버린다.
또, 0을 표현하는 방법이 2가지가 되어버린다.
0은 부호가 있든 없든 0이기 때문에, 00000000 이나 10000000 둘다 0이 된다.
- 2진수 음수를 표현하는 두번째 방법 ~ 1의 보수(1's complement)
: 간단하게 설명하자면, 1의 보수 방법에서 어떤 수의 음수는, 수의 비트를 모두 반전시킨 것이다.
ex) 10진수 15 = 2진수 00001111, 10진수 -15 = 2진수 11110000
0의 음수도 0이므로, 1의 보수에서도 0의 표현방법이 2가지 이다.
ex) 10진수 0 = 00000000, 10진수 -0 = 2진수 11111111
이 방법은 얼핏 보면 연산에 문제가 없어보인다.
2진수 | 10진수 | ||||||||
0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | (= 15) | |
+ | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | (= -15) |
= | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | (= -0) |
그러나 연산 후에 자릿수가 증가하는 경우(carry가 발생하는 경우) 문제가 생긴다.
ex) 16 + (-15) 의 계산
2진수 | 10진수 | ||||||||
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | (= 16) | |
+ | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | (= -15) |
= 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | (= ??) |
이렇게 bit 수가 늘어나는 연산의 경우 결과 값에 1을 더해야 정상적인 값을 얻을 수 있다.
1의 보수 방법을 사용하면 비트만 반전시켜서 음수 값을 얻을 수 있고, 어느 정도 연산이 가능하지만,
캐리가 발생하는 경우 1을 더해주어야 한다는 단점이 있다.
- 2진수 음수를 표현하는 세번째 방법 ~ 2의 보수(2's complement)
: 간단하게 설명하자면, 2의 보수 방법에서 어떤 수의 음수는, 수의 비트를 모두 반전시킨 것에 1을 더한 것이다.
ex) 10진수 15 = 2진수 00001111, 10진수 -15 = 2진수 11110001
0의 음수를 표현하면 11111111 + 1 = 00000000 이 되므로 2의 보수 방법에서 0의 표현방법은 하나가 된다.
2의 보수 방법은 연산 과정에서 캐리가 발생하더라도 발생한 캐리값을 그대로 버리면 된다.
2진수 | 10진수 | ||||||||
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | (= 16) | |
+ | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | (= -15) |
= 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | (= 1) |
컴퓨터는 2의 보수 방법으로 음수를 구한다.
이제 코드에서 num2 = 15 일때 ~num2 = -16이 되는지 이해할 수 있다.
num2 = 00000000 00000000 00000000 00001111
~num2 = 11111111 11111111 11111111 11110000
~num2의 비트를 반전시키고 1을 더하면 ~num2의 음수가 무엇인지 알 수 있다.
~num2의 비트를 반전시키고 1을 더한 값 = 00000000 00000000 00000000 00010000 //(= 16)
~num2의 음수가 16이니 ~num2는 원래 -16이었을 것이다.