글 목록으로 돌아가기

TechNotes

CPU에 감산기가 없는 이유

반가산기와 전가산기, Carry In, 2의 보수를 통해 CPU가 감산기 없이 뺄셈을 수행하는 원리

Dohyeon Kim
Dohyeon Kim 2026년 7월 11일 · 4분 읽기
DeepDive CS LogicCircuit

컴퓨터는 수많은 덧셈과 뺄셈을 수행한다.

그렇다면 CPU 내부에는 덧셈을 위한 가산기(Adder) 와 뺄셈을 위한 감산기(Subtractor) 가 각각 존재할까?

현대 CPU는 대부분 별도의 감산기를 두지 않는다.

대신 가산기 하나만으로 덧셈과 뺄셈을 모두 수행한다.

이 구조를 이해하려면 먼저 반가산기와 전가산기부터 살펴볼 필요가 있다.


반가산기와 전가산기

반가산기(Half Adder)

반가산기는 가장 단순한 덧셈 회로이다.

두 개의 1비트를 더해 합(Sum)자리올림(Carry) 을 계산한다.

A B Sum Carry
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

하지만 반가산기는 이전 자리에서 발생한 Carry를 입력받을 수 없다.

즉, 여러 비트의 덧셈에는 사용할 수 없다.


전가산기(Full Adder)

전가산기는 이전 자리에서 넘어온 Carry까지 계산할 수 있다.

입력은 다음과 같다.

A
B
Carry In

출력은

Sum
Carry Out

이다.

Carry Out은 다음 비트의 Carry In으로 전달된다.

Carry → Carry → Carry


┌────────┐   ┌────────┐   ┌────────┐
│ Full   │──▶│ Full   │──▶│ Full   │
│ Adder  │   │ Adder  │   │ Adder  │
└────────┘   └────────┘   └────────┘

이처럼 전가산기를 여러 개 연결하면 CPU는 8비트, 32비트, 64비트 정수까지 모두 덧셈할 수 있다.

여기까지는 모두 덧셈 회로이다.

그렇다면 뺄셈은 어떻게 수행할까?


감산기를 따로 만들면 되지 않을까?

가장 단순한 방법은 감산기를 하나 더 만드는 것이다.

하지만 그렇게 하면

  • 회로가 복잡해지고
  • 트랜지스터 개수가 증가하며
  • 칩 면적이 커지고
  • 전력 소모도 증가한다.

CPU 설계자는 이미 존재하는 가산기를 그대로 활용하는 방법을 선택했다.

그 결과 등장한 것이 2의 보수(Two’s Complement) 이다.


컴퓨터는 음수를 어떻게 표현하는가

컴퓨터는 메모리에 0과 1만 저장할 수 있다.

따라서 음수를 별도의 기호로 저장하는 것이 아니라 2의 보수를 이용해 표현한다.

2의 보수는 다음과 같이 계산한다.

  1. 양수를 2진수로 표현한다.
  2. 모든 비트를 반전하여 1의 보수를 만든다.
  3. 1을 더한다.

즉,

2의 보수 = 1의 보수 + 1

이다.

예를 들어 -17을 8비트로 표현하면 다음과 같다.

+17

0001 0001

1의 보수

1110 1110

+1

1110 1111

따라서

1110 1111 = -17

이 된다.


2의 보수는 왜 만들어졌을까?

컴퓨터는 음수를 표현하기 위해 2의 보수를 사용한다.

라고만 알고 있었었고, 왜 하필 2의 보수인지는 설명할 수 없었다.

2의 보수는 CPU가 감산기 없이 뺄셈을 수행하기 위해 선택한 방식이다.

전가산기의 기본 연산은

A + B + Carry In

이다.

CPU는 하나의 제어 신호를 이용해 덧셈과 뺄셈을 구분한다.

덧셈

Carry In = 0

A + B

뺄셈

CPU는 B의 모든 비트를 반전시키고 Carry In을 1로 설정한다.

Carry In = 1

A + (~B)

그러면 실제 계산은

A + (~B) + 1

이 된다.

그런데 이 식은

2의 보수 = 1의 보수 + 1

과 정확히 동일하다.

즉,

CPU는

  • B를 반전시키고
  • Carry In에 1을 넣어

하드웨어에서 자동으로 2의 보수를 만든다.

결국

A - B

A + (-B)

로 변환되어

가산기 하나만으로 계산된다.

이것이 CPU에 감산기가 없는 이유이다.


실제로 5 - 5를 계산해 보자

먼저 +5를 표현한다.

0000 0101

-5의 2의 보수는

0000 0101

1111 1010

1111 1011

이다.

이를 더하면

0000 0101
1111 1011
-----------
1 0000 0000

8비트에서는 가장 앞의 Carry를 버린다.

따라서

0000 0000

이 남는다.

즉,

5 + (-5) = 0

이 정상적으로 계산된다.

CPU 입장에서는 뺄셈을 수행한 것이 아니라 음수를 더한 것이다.


-1이면서 동시에 가장 큰 수인 이유

다음 비트를 보면

11111111

이 비트를 signed로 해석하면

-1

이다.

왜냐하면

00000001

의 2의 보수가

11111111

이기 때문이다.

반면 unsigned에서는 부호 비트가 존재하지 않는다.

따라서

11111111

255

가 된다.

비트 signed unsigned
11111111 -1 255

즉,

같은 비트라도 해석 방식에 따라 의미가 달라진다.

강의에서

“11111111은 -1이면서 가장 큰 수도 된다.”

라고 설명한 이유가 이것이다.


왜 -1을 많이 사용할까?

프로그래밍에서는 -1을 특수한 의미로 자주 사용한다.

대표적으로

  • 검색 실패
  • 존재하지 않는 값
  • 초기화되지 않은 인덱스
  • 종료 신호
  • 오류 코드

등을 표현할 때 사용된다.

예를 들어

int index = -1;

은 일반적으로

아직 유효한 인덱스가 없다.

는 의미로 사용된다.

또한

size_t index = -1;

처럼 unsigned 타입에 저장하면 내부적으로는 모든 비트가 1이 되며 해당 자료형의 최댓값으로 해석된다.


정리

  • 반가산기는 두 개의 1비트를 더한다.
  • 전가산기는 Carry In을 이용해 여러 비트의 덧셈을 수행한다.
  • CPU는 별도의 감산기를 두지 않는다.
  • 뺄셈은 B를 반전시키고 Carry In을 1로 설정하여 수행한다.
  • 이는 2의 보수를 만드는 과정과 동일하다.
  • 결국 CPU는 가산기 하나만으로 덧셈과 뺄셈을 모두 처리한다.
  • 같은 비트라도 signed와 unsigned의 해석 방식에 따라 전혀 다른 값이 될 수 있으며, 11111111은 signed에서는 -1, unsigned에서는 최댓값이 된다.

댓글