C언어 비트 음수 표현 🤖
컴퓨터는 모든 데이터를 0과 1의 '비트' 형태로 저장합니다. 전기 신호를 두 가지 상태(켜짐/꺼짐, 1/0)로 표현하여, 하드웨어 구현을 단순화하고 오류를 최소화하며 데이터 처리의 효율성을 제고할 수 있습니다.
컴퓨터는 오직 0과 1의 조합만을 이해할 수 있습니다. 따라서 음수를 표현하는 것은 생각보다 복잡한 문제입니다. C언어를 포함한 대부분의 프로그래밍 언어에서는 음수를 효율적으로 표현하기 위해 특별한 방법을 사용합니다.
1의 보수와 2의 보수는, 음수를 표현하기 위해 많이 사용되는 방식입니다. 특히 2의 보수는 현재 거의 모든 컴퓨터 시스템에서 표준으로 채택되고 있습니다. 이번 글에서는 1의 보수와 2의 보수의 원리, 그리고 각 개념에 대한 실제 예시를 통해 C언어에서 음수가 어떻게 표현되는지 알아보겠습니다.
1의 보수는, 양수의 모든 비트를 뒤집어서 음수로 표현하는 방법입니다. 즉, 0은 1로, 1은 0으로 변경하는 것입니다. 이때, 최상위 비트(MSB, Most Significant Bit)가 1이면 음수, 0이면 양수입니다.
8비트 기준으로 5를 이진수로 표현하면 다음과 같습니다.
00000101 (5의 이진수)
1의 보수 원리에 따르면 -5는 다음과 같이 표현할 수 있습니다.
11111010 (-5의, 1의 보수 표현)
그런데 1의 보수로 음수를 표현하면 +0과 -0이 공존하는 문제가 발생합니다. 8비트 기준으로 0을 이진수로 표현하면 다음과 같습니다.
00000000 (+0의 이진수)
1의 보수 원리에 따라 -0을 표현하면 다음과 같습니다.
11111111 (-0의 이진수)
실제 수학적으로 +0과 -0은 같은 수입니다. 그런데 이진수로는 다르게 표현되므로, 연산이나 비교 시 혼란이 생길 수 있습니다.
다음으로, 4와 -3을 1의 보수 방식으로 더하는 경우를 보겠습니다.
A = 00000100 (4)
B = 11111100 (-3)
00000100
+ 11111100
-----------
(1)00000000 (덧셈 결과)
이진법에서는 1 + 1이 되는 순간 자릿수가 올라가게 됩니다. 위의 경우에서는 8비트를 가정했지만 실제로 한 개 비트가 넘쳐흘러 9비트가 됩니다.
1의 보수에서는 덧셈 결과에서 최상위 자리에서 발생하는 캐리 비트를 다시 오른쪽 끝에 더해주어야 합니다. 이를 end-around carry라고 합니다.
위 덧셈에서 캐리 비트가 1이 발생했으므로, 이를 다시 더해줍니다.
00000000
+ 00000001 ← (캐리)
-----------
00000001
4 + (-3)의 결과, 1이 도출되었습니다.
1의 보수 방식은 end-around carry라는 복잡한 처리와 함께, +0과 -0 문제 때문에 실용성이 떨어집니다. 실제 컴퓨터 시스템에서는 이러한 번거로움을 피하기 위해 대부분 2의 보수 방식을 채택하고 있습니다. 아래에서 자세히 알아보겠습니다.
2의 보수는 1의 보수에 1을 더하는 방식으로 음수를 표현합니다. 즉, 어떤 양수의 2의 보수를 구하고 싶다면, 해당 숫자의 이진수 비트를 모두 반전시킨 후 (1의 보수), 그 결과에 1을 더합니다.
예를 들어, 5의 이진수는 다음과 같습니다.
00000101 (5)
1의 보수는 비트를 반전합니다.
11111010 (1의 보수)
이 상태에서 1을 더합니다.
11111011 → (-5의 2의 보수 표현)
2의 보수를 원래의 양수로 되돌리기 위해서는 1을 빼고, 다시 비트를 반전하면 되겠죠.
+0과 -0이 공존하는 1의 보수의 문제는 다음과 같이 해결됩니다.
2의 보수에서는 -0이 실제로 존재하지 않습니다. 다만 설명 상 "0에 대해 2의 보수를 구해보자"는 의도로 글을 작성했습니다.
00000000 (0의 이진수)
우선 1의 보수 원리에 따라 비트를 전부 반전합니다.
11111111 (-0의 이진수)
이 상태에서 1을 더합니다.
(1)00000000
2의 보수 방식에서는 덧셈 결과가 비트 수를 초과할 경우, 초과된 비트(carry-out)는 무시(버림) 처리하게 됩니다. 따라서 최종 결과는 다음과 같습니다.
00000000
즉, 2의 보수 방식에서는 -0도 결국 +0으로 표현되므로, 단 하나의 0만 존재하게 됩니다. 이로 인해 연산이 간단해지고, 하드웨어도 효율적으로 동작하게 됩니다.
이번에는 4 + (-3)을 2의 보수 방식으로 계산해 보겠습니다.
4 = 00000100
-3 = 11111101 (00000011(3) -> 11111100 -> 11111101)
두 수를 더합니다.
00000100
+ 11111101
-----------
00000001 (9번째 비트는 버림)
2의 보수 방식에서는 덧셈 결과가 비트 수를 초과할 경우, 초과된 비트(carry-out)는 무시(버림) 처리하게 됩니다.
end-around carry라는 복잡한 연산 없이도 정확한 값(1)이 나오는 것을 확인할 수 있습니다.
음수를 이진수로 표현하는 방식은 컴퓨터 구조와 연산의 효율성을 크게 좌우합니다. 초창기에는 1의 보수 방식이 사용되었지만, +0과 -0이 따로 존재하고, end-around carry 같은 복잡한 연산 처리가 필요해 실용성이 떨어졌습니다. 오늘날 C언어를 포함한 대부분의 프로그래밍 언어와 컴퓨터 시스템에서는 2의 보수 방식을 사용해 음수를 표현하고 있습니다.
이진법적 사고는 우리에게 본질을 꿰뚫어 보는 힘을 줍니다. 복잡해 보이는 문제도 결국 가장 기본적인 요소들의 조합으로 이루어져 있다는 것을 깨닫게 합니다. 2의 보수라는 우아한 해법이 탄생한 것처럼, 때로는 가장 단순한 원리에서 가장 강력한 솔루션이 나오기도 합니다. 복잡할수록 가장 단순하고 본질적인 것에 집중하는 우리가 되어야겠습니다.