정수의 산술연산 [ 크래프톤 정글 12일차 ]

jinsung·2025년 5월 24일

크래프톤 정글 9기

목록 보기
10/59

저번 포스트에서 컴퓨터가 2의 보수 표현법을 사용해서 음수를 어떻게 표현하는지 알아봤었다.

그래서 요번에는 정수의 산술연산에 대해 알아보고 2의 보수 표현법을 사용한 경우와 아닌경우 덧셈 뺄셈 등이 어떻게 이뤄지는지 알아보자.

1. 양수와 음수

C 에서 int 자료형을 선언해 본 적이 있나요?

int a = 10000

이 int 자료형은 최대 몇까지 표현되는지 아시나요?

바로 -2,147,483,648부터 2,147,483,647까지입니다.

기본적으로 int 는 4바이트 자료형으로 음수와 양수를 모두 표현하는데 이건 2의 보수 표현법이 적용된거에요.

대부분의 컴퓨터 프로그램에서 음수를 표현할때는 2의 보수 표현법을 사용합니다.

그리고 2의보수 표현법으로 선언한 int 는 앞에 이런게 생략되있어요

signed int a = 10000

signed 입니다. 이건 이 int 를 해석할때 "2의 보수 표현법"으로 해석하겠따는 뜻이예요.

만약 이렇게 선언하면 어떻게 될까요?

unsigned int a = 10000

이건 2의 보수 표현법으로 해석하지 않고 그냥 단순한 이진비트로 해석하겠다는 뜻이예요.

제가 예시를 들어볼게요.

  • 1110 이라는 비트가 있습니다.

이건 일반 이진수처럼 계산할 때는

1x2^3 + 1x2^2 + 1x2^1 + 0x2^0 = 7입니다.

이건 unsigned int a = 7 을 해석한 것과 같아요.

이걸 2의 보수표현법으로 계산할때는

-1x2^3 + 1x2^2 + 1x2^1 + 0x2^0 = -2 입니다.

이건 int a = -2 와 같아요.

같은 1110 을 해석했는데 unsigned 와 signed 의 값이 다르죠?

signed 와 unsigned 는 앞에 붙인다고 비트가 달라지진 않아요. 단지 "그걸 해석하는 방법"이 달라집니다.

같은 1111 ( max ) 라도
signed 로 해석할 때는 -1 이 되고
unsigned 로 해석할 때는 15가 되요.

그래서 이건 정수끼리의 덧셈 혹은 다른 산술연산을 할 때 문제를 발생시킵니다.

2. 덧셈과 오버플로우

예를 들어 이렇게 선언한 정수가 있다고 해볼게요

signed int a = 2147483648
unsigned int b = 2147483649

2147.. << 얘는 signed int 자료형의 최대치인데요.
int b 가 자료형의 최대치를 넘어섰음에도 유지될 수 있는 이유는 값의 범위가 달라지기 때문입니다.

  • signed int = -21억 ~ 21억
  • unsigned int = 0~42억

왜 이렇게 되냐면

=> 1 111111111111111111111111111111111111 signed 에서 맨 앞 1은 부호비트로 사용
=> 1111111111111111111111111111111111111 unsigned 에서 맨 앞 1도 연산에포함!

이래서 unsigned 는 더 큰 값을 범위로 가질 수 있는거예요.

오버플로우 문제

이 코드 한번 보실래요?

signed int a = 2147483647; // int 최대값
signed int b = 1;

int result = a + b;
printf("%d\n", result);

이 코드의 결과는 -2147483648 입니다. 왜그럴까요?

이걸 비트단위로 보면

a =  01111111 11111111 11111111 11111111  (2147483647)
b = +00000000 00000000 00000000 00000001
----------------------------------------
    =10000000 00000000 00000000 00000000  (-2147483648)

인데요. int 는 4byte 이기 때문에 이 범위를 초과하면 가장 앞자리가 잘리거나 해석이 바뀌는 거예요.

저 위의 덧셈결과는 2의보수표현법으로 가장 큰 음수값에 해당돼요. -1x2^32 과 같죠

언더플로우 문제

이 코드도 봐주세요

signed int a = -2147483648; // int 최소값
signed int b = -1;

int result = a + b;
printf("%d\n", result);

이 코드의 결과는 2147483648 이예요. 이것도 이상하죠?

a = 10000000 00000000 00000000 00000000  (-2147483648)
b = 11111111 11111111 11111111 11111111  (-1)
----------------------------------------
    =01111111 11111111 11111111 11111111  (2147483647)

가장 왼쪽 비트가 1이면 음수로 해석되는데 덧셈결과가 그자리를 0으로 만들어서 양수로 바뀌어버린거예요.

signed 정수형에서는 오버플로우나 언더플로우는 에러예요. 결과가 다를 수 있고 예측 불가능한 버그를 유발할 수도 있어요.

unsigned int 의 경우엔 덧셈에 모듈러 연산을 실행하기 때문에 값이 넘치면 2^32 로 나눈 나머지가 자동으로 계산돼요.

unsigned 오버플로우

unsigned int a = 4294967295; // 최대값 (2^32 - 1)
unsigned int b = 1;

unsigned int result = a + b;
printf("%u\n", result); // 결과: 0

unsigned 는 모듈러 연산을 실행하기 때문에 값이 넘치면 2^32 로 나머지 연산을 한다고 했죠?

그래서 0이 된거예요.

unsigned 와 signed 를 더하면 어떻게 될까?


그런건 하지 않는게 좋습니다. 그냥 하지마세요.

단지 암묵적 형변환으로 더 큰 정수형으로 변경된다는것.

1개의 댓글

comment-user-thumbnail
2025년 5월 24일

부동소수점 글도 올라오길 기원 1일차

답글 달기