본문 바로가기
파이썬/파이썬 기초

1의 보수, 2의 보수, Signed와 Unsigned의 모든 것

by Go! Jake 2021. 5. 7.

 

Unsigned와 Signed

Signedness는 컴퓨터 프로그래밍에서 숫자를 표현하는 데 쓰인다. 데이터 타입과 같은 속성이라고 보면 된다.

Signed는 양수와 음수를 표현할 수 있다. Unsigned는 non-negative numbers, 즉 0과 양수를 표현할 수 있다.

 

Unsigned

Unsinged는 Sign과 다르게, 가장 왼쪽 bit인 MSB (Most Significant Bit)가 + 또는 - 부호를 표현하지 않는다. 모든 bit가 숫자를 표현하는 데 사용된다. 따라서, 8bit인 경우 범위는 0부터 255를 표현할 수 있다.

 

Unsigned Integer
출처: If an unsigned int is given a negative value? - Quora

Signed

우선, Signed에서 맨 앞에 있는 MSB는 + 또는 - 부호를 나타낸다. 1인 경우 -0 또는 음수이며, 0인 경우 +0 또는 양수이다.

Signed는 가장 왼쪽 bit인 MSB(Most Significant Bit)가 + 또는 - 부호 표현에 사용된다. 따라서 나머지 bit는 숫자 표현에 사용된다.

모든 bit 중 하나의 bit는 숫자를 사용하지 않게 되므로, 숫자 범위 표현에 있어 bit가 하나 줄어들게 된다. 예를 들어, 8-bit 정수는 -128에서 127까지 표현할 수 있다.

 

Signed Integer
출처: https://www.quora.com/If-an-unsigned-int-is-given-a-negative-value

  • 0을 표현하는 방법은 두 방법이 있다. 00000000 (0)과 10000000 (-0)
  • 덧셈과 뺄셈은 sign bit에 따라 다르게 동작한다. 또한 이때 사용되는 '1의 보수'와 '2의 보수' 개념에 따라 계산 방법이 달라지게 된다
  • 음수의 최솟값은 '2의 보수'에서는 -128 대신 -127까지 표현된다.

보수의 목적

Signed 쓰임을 온전히 이해하기 위해서는 보수(Complement)의 표현을 이해해야 한다.

컴퓨터에서는 1의 보수에 대한 문제점으로, 주로 2의 보수를 사용한다.

컴퓨터 연산은 2진수와 사칙 연산을 사용한다. 이때 문제점은 컴퓨터는 음수의 표현이 불가능하다. 따라서 데이터의 범위를 음수와 양수로 나눠 사용한다. 2의 보수를 예를 들면 범위를 나눌 때, '나열된 값'과 '나열된 값에 대한 보수'를 양수와 음수로 나누어 사용한다. e.g. 4bit를 나눈다고 하면,-8(8), -7(9),....., 0(15), 1, 2, 3,...., 7가 된다.

 

보수 표현을 활용하여 사칙 연산이 가능하다. 덧셈은 덧셈, 뺄셈은 보수의 개념, 곱셈은 더하기를 여러 번 중첩하고 나누기는 뺄셈을 여러 번 중첩하며 계산한다. 보수의 개념은 연산에서도 필수적이므로 개념을 숙지할 필요가 있다.

 

기본적으로 프로그래밍에서는 뺄셈 계산을 어떻게 할 지에 대한 논의가 많았다. Signed에서 뺄셈을 수행하면, 0001(1) + 1001(-1) = 1010 (-2)가 되기 때문에 정상적인 값이 되지 않는다. 따라서, 단순히 MSB가 1이어서 뺄셈이 되는 게 아니라, Signed 된 binary에 수를 정의해야만 뺄셈이 정상적으로 수행될 수 있다는 것을 알게 된다.

 

따라서, 프로그래밍에서 연산을 쉽게 만드는 '1의 보수'와 '2의 보수'의 정의에 대해 알아보자.

 

 

 

1의 보수 

1에 대한 보수를 구하는 방법은 어떠한 binary 값에서 bitwise NOT을 사용하면 된다.

01111101(2)에 대한 1의 보수 값은,10000010(2)이 된다.

 

아래 차트를 살펴보자.

Eight-bit ones' complement
Binary value Ones' complement interpretation Unsigned interpretation
00000000 +0 0
00000001 1 1
01111101 125 125
01111110 126 126
01111111 127 127
10000000 −127 128
10000001 −126 129
10000010 −125 130
11111101 −2 253
11111110 −1 254
11111111 −0 255

이 학습에서는 기준점에 대한 정의가 중요하다. Binary값인 1열과 1의 보수 개념을 적용한 값인 2열, Unsigned값인 3열을 살펴보자.

00000000은 +0으로 정의하였고, 11111111는 -0로 정의하여 정중앙을 기준으로 수를 나누었다. 이후 서술되는 '2의 보수'와 차이가 있다.

1의 보수는 음수를 표현할 수 있으며 1의 보수의 범위는 -127에서 127, +0과 -0으로 구성된다. 음수의 경우 0의 개수가 늘어날수록 절댓값이 커진다. 종이에 써 가며 계산해 보자.

눈에 띄는 점은, 음수일 때 10000000(2)의 경우 -127이 되며, 1이 늘어나면서 11111111(2)이 되는 경우 -0이 된다. 보수에서의 숫자 개념을 이와 같이 정의를 따로 내린 것이다.

 

앞서 살펴본 01111101(2)은 125이며, 이에 대한 1의 보수 값은 bitwise NOT이므로 10000010(2)이므로 -125가 된다. 1의 보수 표현으로 위와 같이 차트를 정의하고 음수의 개념을 정의하였을 때, 연산을 수행하면 몇 가지 규칙이 생기게 된다.

 

1의 보수를 이용한 뺄셈은 빼는 수에 1의 보수를 변환하고, 이를 더한다.

1) 이때 자릿수가 전체 bit 개수 대비 증가하면, 계산된 값에 1을 더해준다.

2) 전체 bit 개수 대비 자릿수가 증가하지 않았다면, 그대로 답이 나온다.

 

<1의 보수 연산 Example 1 - 덧셈>

    binary    decimal
   11111110     −1
+  00000010     +2
───────────     ──
 1 00000000      0   ← Not the correct answer
          1     +1   ← Add carry
───────────     ──
   00000001      1   ← Correct answer

11111110(-1)과 00000010(2)을 연산할 때, 1 00000000과 같이 기존 bit 이상으로 넘어가면, 이를 계산된 값에 더해준다.

따라서 0000001 (1)이 된다. 1을 계산된 값에 더해주는 것을 'end-around carry'라고 한다.

1의 보수에서의 값이 익숙하지 않다면 Eight-bit ones' complement 차트로 돌아가서 하나씩 살펴본다.

 

<1의 보수 연산 Example 2 - 뺄셈>

  0000 0110      6
− 0001 0011    -19
===========   ====
  0000 0110      6
+ 1110 1100    -19
===========   ====
  1111 0010    -13

0000 0110(6) - 0001 0011(-19) = 0000 0110(6) + 1110 1100 (-19, 1의 보수 표현) = 1111 0010 (-13)이 되므로 정상적인 계산이 된다.

 

처음에는 이 메커니즘에 대해 많은 고민을 해 보려 하였지만, '1의 보수'라는 개념으로 위 차트와 같이 수를 정의하였을 때, 단순히 1의 보수를 찾고 이를 더하는 것은 정상적인 연산을 위해  테크니컬 한 연산을 하는 것이기 때문에 크게 신경 쓰지 않기로 하였다.  즉 위 규칙은 '1의 보수'를 정의하여 사용하였을 때 정상적인 연산을 위해 사용되는 연산 메커니즘인 것이다.

 

1의 보수의 문제점

1의 보수는 문제점이 있다. +0과 -0이 존재한다는 점에서 문제점이 있다. 0000과 1111을 모두 0으로 처리해야 하며, 계산과정에서 자릿수 변경에 따라 계산 합에 1을 더해줘야 하는 'end-around carry' 문제가 있다. 아래 2의 보수가 제안되었다.

 

2의 보수

2의 보수는 1의 보수에서의 +0과 -0의 문제점을 해결하고, 자릿수가 커짐에 따라 계산 합에 1을 더 해 주는, 'end-around carry' 문제를 극복하도록 정의할 수 있다.

2의 보수는 signed 정수를 표현하는 데 있어 가장 흔한 방법이다. 1의 보수와 마찬가지로 bitwise NOT으로 값을 반전하고, 1을 더한 이다. 차트를 보면 아래와 같다. 

Eight-bit two's complement
Binary value Two's complement interpretation Unsigned interpretation
00000000 0 0
00000001 1 1
01111110 126 126
01111111 127 127
10000000 −128 128
10000001 −127 129
10000010 −126 130
11111110 −2 254
11111111 −1 255

이 학습에서도 '1의 보수'와 마찬가지로 기준점에 대한 정의가 중요하다.

Binary값인 1열과 2의 보수 개념을 적용한 값인 2열, Unsigned값인 3열을 살펴보자.

00000000은 0으로 정의하였고, 11111111는 -1로 정의하였다. 정 중앙에서 +0와 -0으로 구분 지었던 '1의 보수'와 차이가 있다.

 

2의 보수도 마찬가지로 음수를 표현할 수 있다. 위 정의에 따라 -128에서 127까지 구성되며, 하나의 0을 갖는다. 눈에 띄는 점은 0이 하나라는 점이다. 마찬가지로  음수의 경우 0의 개수가 늘어날수록 절댓값이 커진다.

2의 보수에서 '음수'에 한하여 '1의 보수' 값보다 절댓값으로 1보다 큰 값을 갖는다. 예를 들어, 1의 보수에서의 10000000은 -127인 반면, 2의 보수에서 10000000은 -128의 값을 갖는다. 서술한 대로, 1의 보수와 마찬가지로 bitwise NOT으로 값을 반전하고, 1을 더한 값이다.

 

예를 들어 +2의 binary값에 대해 2의 보수 값을 찾아보자.

1. ~00000010 (2) -> 11111101 (-2)

2. 11111101 + 1 -> 11111110 (binary 2 값은, 2의 보수로 '-2'를 의미한다.)

 

2의 보수에서의 뺄셈은 빼는 수를 2의 보수로 한번 변환하고, 이를 더한다.

1) 이때 자릿수가 전체 bit 개수 대비 증가하면, 자리올림을 제외한 계산된 값이 답이다.

2) 전체 bit 개수 대비 자릿수가 증가하지 않았다면, 그대로 답이 나온다.

 

<2의 보수 연산 Example 1 - 덧셈>

    binary    decimal
   11111111     −1
+  00000010     +2
───────────     ──
 1 00000001      1   ← Correct answer

결과 값을 보면, 2의 보수 개념에서는 1111 1111이 -1이므로, 1111 0011은 -13이 된다. 따라서 1의 보수에서 +0과 -0 개념을 혼동할 일이 없고, 또한 자리 올림에 대해 걱정할 필요도 없다. 계산 그대로 나온다.

 

<2의 보수 연산 Example 2 - 뺄셈>

  0000 0110      6
− 0001 0011    -19
===========   ====
  0000 0110      6
+ 1110 1101    -19
===========   ====
  1111 0011    -13

결과 값을 보면, 2의 보수 개념에서는 1111 1111이 -1이므로, 1111 0011은 -13이 된다. 따라서 1의 보수에서 +0과 -0 개념을 혼동할 일이 없고, 또한 자리 올림에 대해 걱정할 필요도 없다. 계산 그대로 나온다.

 

 

정리

  • Unsigned와 Signed 표현이 있고, Unsigned는 0에서부터 양수를 표현하며 Signed는 가장 왼쪽 비트인 MSB(Most Significant Bit)가 1인 경우 음수, 0인 경우 양수를 나타낸다.
  • 컴퓨터에서는 음수 표현을 할 수 없기 때문에 범위를 잘라서 양수와 음수로 표현한다. 이때 나열된 수와 나열된 수의 보수가 양수와 음수를 표현한다.
  • 1의 보수와 2의 보수가 있으며 1의 보수는 +0과 -0, End-around carry 처리를 해야 하는 문제가 있기 때문에 2의 보수를 주로 사용한다.
  • 1의 보수는 bitwise NOT을 통해 값을 구할 수 있고, 2의 보수는 bitwise NOT 값에 +1을 더해 구할 수 있다.

 

Reference

Signed number representations - Wikipedia

Signedness - Wikipedia

Ones' complement - Wikipedia

Two's complement - Wikipedia

 

댓글