
저번 포스트에서 컴퓨터가 2의 보수 표현법을 사용해서 음수를 어떻게 표현하는지 알아봤었다.
그래서 요번에는 정수의 산술연산에 대해 알아보고 2의 보수 표현법을 사용한 경우와 아닌경우 덧셈 뺄셈 등이 어떻게 이뤄지는지 알아보자.
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의 보수 표현법으로 해석하지 않고 그냥 단순한 이진비트로 해석하겠다는 뜻이예요.
제가 예시를 들어볼게요.
이건 일반 이진수처럼 계산할 때는
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가 되요.
그래서 이건 정수끼리의 덧셈 혹은 다른 산술연산을 할 때 문제를 발생시킵니다.
예를 들어 이렇게 선언한 정수가 있다고 해볼게요
signed int a = 2147483648
unsigned int b = 2147483649
2147.. << 얘는 signed int 자료형의 최대치인데요.
int b 가 자료형의 최대치를 넘어섰음에도 유지될 수 있는 이유는 값의 범위가 달라지기 때문입니다.
왜 이렇게 되냐면
=> 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일차