Technology/Computer Architecture

보수의 개념(2진법과 비트, 바이트, 1의 보수, 2의 보수)

ikjo 2022. 1. 11. 03:29

 

 

2진법과 비트

2진법은 컴퓨터에서 입력과 출력을 표현하기 위한 표준 방법으로서 오직 0과 1(이진수)로만 데이터(정보)를 표현한다. 컴퓨터는 이러한 0과 1만의 숫자를 통해 글자, 사진, 영상, 소리 등을 저장할 수 있다. 컴퓨터의 가장 기본적인 단위는 트랜지스터라고 불리는 아주 작고 간단한 전기 스위치로, 이 트랜지스터의 on/off 상태를 통해 0과 1을 표현한다. 이때 2진수 상 각 하나의 자릿수를 표현하는 단위를 비트(bit)라고 하며 컴퓨터는 비트 단위로 정보를 처리한다.

 

 

바이트

비트 한 개만으로는 많은 양의 정보를 처리하기 부족하므로 바이트(byte)를 사용한다. 바이트는 8개의 비트열로서, 1바이트에는 여덟 개의 비트가 있고, 비트 하나는 0과 1로 표현될 수 있기 때문에 1바이트는 총 256(=2^8)개의 서로 다른 바이트로 표현될 수 있다. 또한 1바이트는 8개의 비트이므로 8개의 트랜지스터라고 할 수 있다.

 

단위 정의 저장공간 크기
비트(bit) 0 또는 1 True 또는 False
바이트(byte) 8비트 영어 알파벳 한 개
킬로바이트(KB) 1024바이트
메가바이트(MB) 1024킬로바이트 음악(MP3)
기가바이트(GB) 1024메가바이트 HD 영화
테라바이트(TB) 1024기가바이트 드라마 시리즈 모음

 

 

보수

컴퓨터는 앞서 언급한 대로 데이터를 연산(CPU)할 때 2진수를 사용한다. 이때 2진수를 연산하기 위해서 컴퓨터는 가산기를 사용한다. 가산기는 말 그대로 더하는 계산기이다. 이때 곱셈은 여러번 더함으로써 구현해낼 수 있다. 하지만 뺄셈은 어떻게 구현할까? 이때 사용되는 개념이 바로 보수(Complement)의 개념이다. 보수는 덧셈을 이용하여 뺄셈을 구현하는 방식이다. 반대로 나눗셈은 보수를 이용한 뺄셈을 여러 번 해주면 구현할 수 있다. 즉, 보수를 잘만 이용하면 가산기만을 이용하여 4칙연산을 모두 구현해낼 수 있는 것이다.

 

십진수 연산의 예를 들어보자. 우리는 모두 14 - 7은 7이라는 것을 쉽게 구할 수 있다. 하지만 컴퓨터는 어떻게 구할까? 앞서 언급했듯이 컴퓨터는 -7을 표현하기 위해 보수를 이용해야한다. -7을 표현하기 위해서는 10진수 7의 보수를 구하면 된다. 7의 보수를 구하는 방법은 우선 부호를 바꿔준 -7에다가 10을 더해주면 된다. 즉, 10진수 7의 보수는 3이다. 이때 14와 3을 더해준다. 그러면 17이 된다. 여기서 앞자리수(십의자리수) 1을 빼면 7이 남는데, 우리가 구한 14-7=7의 연산 결과와 일치한다. 컴퓨터는 이러한 방식으로 뺄셈을 구현한다.

 

 

1의 보수와 2의 보수

계속 반복적으로 얘기하지만 컴퓨터는 데이터를 연산하는데 2진수를 사용한다. 따라서 앞선 예시에서 10진수의 보수를 컴퓨터에서 구할 일은 많지 않다. 컴퓨터는 사용자가 입력한 10진수를 2진수로 바꿔준 후 2진수의 보수를 구하여 뺄셈 등의 연산을 한다. 이때 2진수의 보수를 구하는 방법은 1의 보수를 구하는 방법과 2의 보수를 구하는 방법이 있다. 정확하게는 1의 보수를 구하는 방법이 먼저 생겼고 여기에 문제점이 있어 개선된 방식이 2의 보수를 구하는 방법이다.

 

1의 보수 구하기

1의 보수를 구하는 방법은 1은 0으로, 0은 1로 바꾸어주면 된다. 즉 해당 이진수에 XOR 연산을 해주면 되는 것이다. 예를 들어 컴퓨터가 -10을 표현한다면 10의 이진수 1010에 대한 1의 보수를 구하여 0101을 만든다.

 

1의 보수를 이용한 연산

그러면 이렇게 구한 1의 보수를 가지고 연산을 해보자. 우리는 13 - 10 = 10(1101 - 1010 = 0011)이라는 것을 바로 알 수 있다. 하지만 컴퓨터는 -10을 표현하기 위해 앞선 과정을 통해 1의 보수를 구한 0101의 이진수를 이용한다. 13은 이진수로 표현하면 1101이다. 이 둘을 연산해보자.

 

 

연산 결과 10010이 나왔는데, 1의 보수를 이용한 연산에서 특이한 점은 연산 결과 한 자리가 더 길어진 경우 캐리 값 즉, 최상위 비트를 최하위 비트에 더해주는 것이다. 이렇게 되면 0011이라는 결과가 나오며 앞서 우리가 구한 13 - 10 = 10(1101 - 1010 = 0011)과 일치한 값이다.

 

다음은 19 - 3 = 16(0101 1011 - 0000 0011 = 0001 0000)을 1의 보수를 구하여 연산한 방식인데 앞서 언급한 내용과 동일하다.

      00010011 (19)
  +) 11111100 (-3; 3에 대한 1의 보수)
     -----------
    100001111 (15; 1의 Carry 발생)
  +) 00000001 (Carry)
     -----------
     00010000 (16; 최종 결과)

※ 참고자료 : https://ko.wikipedia.org/wiki/1%EC%9D%98_%EB%B3%B4%EC%88%98

 

하지만 10 - 13 = -3(1010 - 1101 = -0011)의 연산의 경우 아래와 같이 캐리가 발생하지 않는다. 이때는 최종 결과값에서 다시 1의 보수를 구한 다음에 - 부호를 붙여주면 된다. 연산 결과 우리가 구한 결과값과 동일하다. 다만 여기에 부호(sign) 비트를 추가하면 답은 10011이다.

1의 보수의 문제점

이때 1의 보수의 문제점이 있는데 +0은 0000 0000으로 나타낼 수 있는 반면, -0은 1111 1111로 1의 보수로 인해 0을 표현하는 방법이 2개가 존재하게 되는 것이다. 이러한 문제점을 개선하고자 나온 것이 2의 보수이다.

 

2의 보수 구하기

2의 보수를 구하는 것 자체는 쉽다. 단지 1의 보수를 구한 것에 1을 더해주면 된다. 예를 들어 십진수 10(1010)을 1의 보수로 표현하면 0101이다. 여기에 1을 더하면 0110인데, 이게 바로 2의 보수이다.

 

2의 보수 연산하기

이번엔 2의 보수를 이용하여 연산해보자. 우리는 13 - 10 = 3(1101 - 1010 = 0011) 이라는 것을 직관적으로(또는 계산해서) 알 수 있다. 이때 컴퓨터는 -10을 2의 보수로 표현하여 가산해주는데, 연산 결과 한 자리가 더 길어진 경우 즉, 캐리 값이 발생한 경우 1의 보수 연산과 달리 그냥 버린다. 연산 식과 결과는 아래와 같다.

 

 

이번엔 10 - 13 = -3(1010 - 1101 = -0011)을 확인해보자. 1101을 2의 보수로 취하면 0011이다. 이를 1010과 더하면 1101이 나오는데 이때 캐리가 발생하지 않았으므로 연산 결과를 다시 2의 보수로 취해준 후 - 부호를 붙여준다. 연산 식과 결과는 아래와 같다.

 

 

아울러 100 - 75 = 25(0110 0100 - 0100 1011 = 0001 1001)를 2의 보수를 구하여 연산한 결과는 다음과 같다.

       01100100
   +) 10110101
      -----------
     100011001

새로 생긴 가장 높은 자리의 숫자를 빼고 남은 00011001은 십진수로 25와 같으며 이는 계산하려던 식의 결과이다.

 

※ 참고자료 : https://ko.wikipedia.org/wiki/2%EC%9D%98_%EB%B3%B4%EC%88%98

 

1의 보수의 문제점을 개선한 2의 보수

앞서 1의 보수의 경우 +0은 0000 0000, -0은 1111 1111이었다. 하지만 2의 보수의 경우 +0은 0000 0000, -0은 0000 0000로 0을 표현하는 방법은 딱 하나다. -0이 0000 0000인 이유는 2의 보수를 취하는 과정에서 캐리가 발생했기 때문에 캐리를 버렸기 때문이다.

※ 발생한 캐리를 버렸다고 표현했지만 실제로 이는 CPU 레지스터 중 Flag 레지스터에 저장된다.(올림이 되었는지를 저장)

 

그럼 2의 보수로서 1111 1111은 이제 무엇을 표현하는 걸까? 바로 -1이다. 1을 1의 보수로 취하면 1111 1110이며 여기에 1을 더하면 1111 1111이 된다.

 

지금까지 굳이 8자리의 2진수(8bit)를 예시로 든 이유는 사실 1byte의 정수 범위를 설명하기 위함이었다. 이때 음수를 표현하기 위한 2의 보수의 2진수양수를 그대로 2진수로 표현한 수는 겹쳐서는 안된다. 앞서 0은 0000 0000이었고, -1은 2의 보수로서 1111 1111이었다. 이때 양수는 1씩 증가할 것이고 음수는 1씩 감소할 것이다. 이렇게 쭉 가다보면 중간에 만나는 지점이 있는데 그 지점이 바로 0111 1111(127)과 1000 0000(-128)이다.

 

앞서 다룬 것을 미루어 보았을 때 8bit로 구성된 1byte의 표현 가능한 정수 범위는 -128 ~ 127이라고 결론을 내릴 수 있을 것이다. 또한 컴퓨터에 저장되는 모든 데이터들은 2진수 형태(0과 1)로 바뀌어 저장되며 양의 정수는 2진수 형태 그대로 저장되겠지만 이처럼 음의 정수는 "2의 보수 표현 방법"으로 저장된다는 것을 알 수 있을 것이다.

 

 

참고자료

  • 부스트코스 모두를 위한 컴퓨터 과학(CS50)
  • 유튜브 대멀쌤
  • https://sessionk.tistory.com/126