← 모두의 툴

2의 보수, 컴퓨터가 음수를 표현하는 방법

가이드 · 2026.08.21 최종 확인

진수 변환기에서 아무 숫자나 넣고 부호 있는 정수(Signed 32bit) 값을 보면, 이진수 표현이 사람 직관과 어긋나는 순간이 옵니다. 예를 들어 32비트가 전부 1인 0xFFFFFFFF는 "이진수로 제일 큰 수"처럼 보이지만 실제로는 -1입니다. 이건 오류가 아니라 컴퓨터가 음수를 저장하는 방식, 즉 2의 보수(two's complement) 표현법 때문에 생기는 결과입니다.

1. 왜 부호비트 하나로는 부족한가

가장 단순한 음수 표현 방식은 "부호와 크기(sign-magnitude)"입니다. 최상위 비트를 부호로 쓰고 나머지 비트로 절댓값을 표현하는 방식인데, 직관적이지만 두 가지 문제가 있습니다. 하나는 0이 두 가지(+0, -0)로 존재한다는 것이고, 다른 하나는 덧셈·뺄셈 회로를 부호에 따라 분기 처리해야 해서 하드웨어가 복잡해진다는 것입니다. 2의 보수는 이 두 문제를 동시에 해결하기 위해 고안된 표현법으로, 현재 거의 모든 CPU가 정수 연산에 이 방식을 사용합니다.

2. 2의 보수를 만드는 방법

어떤 양수 n의 음수 표현을 구하려면 모든 비트를 반전(1의 보수)한 뒤 1을 더하면 됩니다. 8비트 예로 살펴보면, 1은 00000001이고 이를 반전하면 11111110, 여기에 1을 더하면 11111111이 나옵니다. 이것이 -1의 8비트 표현입니다. 32비트에서는 이 과정을 그대로 32자리에 적용하면 되고, 결과적으로 모든 비트가 1인 값(0xFFFFFFFF)이 -1이 됩니다. 반대로 최상위 비트만 1이고 나머지가 0인 0x80000000은 32비트 부호 있는 정수의 최솟값인 -2,147,483,648입니다.

핵심 규칙: 32비트 정수에서 최상위 비트(MSB)가 1이면 음수, 0이면 양수입니다. 음수의 실제 값은 "2^32 - (비트 패턴을 부호 없는 수로 읽은 값)"과 같습니다. 예: 0xFFFFFFFF → 2^32 - 4294967295 = 1이므로 -1.

3. 0이 유일한 이유

부호-크기 방식에서는 +0(00000000)과 -0(10000000)이 별도로 존재해 같은 값을 두 가지 비트 패턴으로 표현하는 낭비가 생깁니다. 반면 2의 보수에서 0을 반전하고 1을 더하면 00000000 → 11111111 → (자리올림 발생) 00000000, 즉 다시 자기 자신으로 돌아옵니다. 그래서 2의 보수 표현은 0에 대응하는 비트 패턴이 정확히 하나뿐이고, 그만큼 표현 가능한 범위를 하나 더 확보할 수 있습니다(예: 8비트 기준 -128~127로, 음수 쪽이 양수 쪽보다 1개 더 많음).

4. 덧셈 회로가 단순해지는 이유

2의 보수의 진짜 장점은 부호를 신경 쓰지 않고 그냥 이진수 덧셈을 하면 뺄셈까지 저절로 처리된다는 것입니다. 예를 들어 5 - 3은 5 + (-3)으로 바꿔서 그냥 더하면 됩니다. 8비트로 보면 00000101(5) + 11111101(-3) = 100000010이 되는데, 8비트를 넘어가는 최상위 자리올림은 버리므로 00000010, 즉 2가 남습니다. CPU 입장에서는 덧셈기 하나만 있으면 부호 있는 정수의 덧셈과 뺄셈을 모두 처리할 수 있어 회로가 크게 단순해집니다. 진수 변환기에서 직접 여러 값을 넣어 Signed 32bit 결과를 확인해보면 이 원리를 눈으로 체감할 수 있습니다.

5. 진수 변환기가 실제로 처리하는 방식

이 계산기의 코드를 확인해보면 입력값을 n >>> 0 연산으로 32비트 부호 없는 정수로 바꿔 Unsigned 값을 표시하고, n | 0 연산으로 32비트 부호 있는 정수로 바꿔 Signed 32bit 값을 표시합니다. 두 연산 모두 JavaScript 엔진 내부에서 정확히 2의 보수 규칙을 따르므로, 힌트에서 언급한 대로 0xFFFFFFFF를 입력하면 Unsigned는 4294967295, Signed는 -1이 정확히 출력됩니다. 32비트 이진 비트 그리드도 함께 표시되므로 최상위 비트가 1인지 눈으로 바로 확인할 수 있습니다.

16진수Unsigned(부호 없음)Signed 32bit(2의 보수)
0x0000000111
0x7FFFFFFF2,147,483,6472,147,483,647 (최댓값)
0x800000002,147,483,648-2,147,483,648 (최솟값)
0xFFFFFFFF4,294,967,295-1

자주 묻는 질문

Q. 왜 최상위 비트가 1이면 무조건 음수인가요?

2의 보수 표현에서 최상위 비트는 실질적으로 "-2^(비트수-1)" 자리의 가중치를 가집니다. 32비트라면 최상위 비트가 1일 때 -2^31(약 -21억)이라는 큰 음수 값을 더하는 효과가 나서, 나머지 비트가 무엇이든 전체 값이 반드시 음수가 됩니다.

Q. 오버플로우는 왜 생기나요?

2,147,483,647(0x7FFFFFFF, 32비트 부호 있는 정수 최댓값)에 1을 더하면 비트 패턴이 0x80000000이 되어 최솟값인 -2,147,483,648로 뒤바뀝니다. 이런 현상을 정수 오버플로우라 하며, 2의 보수 구조의 자연스러운 부산물입니다.

Q. 64비트 시스템에서도 원리가 같나요?

네, 비트 수만 32에서 64로 늘어날 뿐 반전 후 1을 더하는 규칙과 최상위 비트가 부호를 결정하는 원리는 동일합니다. 다만 이 진수 변환기는 32비트 기준으로 동작하므로, 64비트 값을 정확히 다루려면 BigInt를 지원하는 별도 도구가 필요합니다.

Q. 부동소수점(float) 음수도 2의 보수인가요?

아닙니다. 부동소수점은 IEEE 754 표준에 따라 별도의 부호 비트 하나만 사용하고(부호-크기 방식과 유사), 지수부·가수부가 따로 있습니다. 2의 보수는 정수 연산에서만 사용되는 표현법입니다.