C :: 자료형의 범위를 구해보자. - 정수
long double 자료형의 범위를 구하겠다고 시작한 일이 쉽지만은 않네요. 그래서 쉬운 것부터, 정수형 자료형의 범위를 구하는 것부터 시작하였습니다.
처음에는 무작정 1씩 더해가는 방식으로 해봤습니다. 무지 비효율적입니다. OTL. 그 다음에 시도한 것은 pow() 함수를 이용하여 더해가는 방식을 사용했습니다. 멍청한 거죠? 그냥 pow() 함수로 구하면 되는 것을요. 그땐 왜 더한다는 생각만 했던지. 생각 해보니까 컴퓨터는 이진수를 다루기 때문에 더할 필요 없으니 2의 거듭승만 구하면 되겠더라구요. 하지만 pow() 함수도 비효율적입니다. 음수를 거듭제곱하면 양수가 되니까요.
그래서 마지막으로 사용한 방법이 비트 연산과 오버플로어를 이용한 것입니다. 쉬프트 연산을 말하는 거죠. 쉬프트 연산은 간단히 말해서 2배, 혹은 1/2배로 계산하지만 비트 단위로 연산하기 때문에 효율성에서 최고더라구요. 아래 코드를 볼까요?
/************************************************************************
* 프로젝트 이름 : type in GCC *
* 프로젝트 목적 : GCC 컴파일러에서 자료형의 범위를 구한다. *
* 소스파일 이름 : main.c *
************************************************************************/
// 입출력을 위해 stdio.h를 부른다.
#include <stdio.h>
int main(void)
{
int number = 1;
int freq = 1;
while(number > 0)
{
number <<= 1;
printf("freq = %d, number = %d \n", freq++, number);
}
printf("\n이 자료형의 범위는 %d ~ %d 입니다. \n", number, ~number);
return 0;
}
변수 number는 1단위씩 왼쪽 쉬프트 연산을 합니다. 즉, 2배씩 곱해지는 거죠. 이렇게 계속 쉬프트 연산을 하다가 number가 0보다 작거나 같을 때 연산이 중단됩니다. 0보다 작거나 같을 때를 조건으로 한 이유는 오버플로어 때문입니다. 직접 비트를 볼까요?
freq == 30 일 때, 01000000 00000000 00000000 00000000
freq == 31 일 때, 10000000 00000000 00000000 00000000
freq == 32 일 때, 00000000 00000000 00000000 00000000
쉬프트 연산을 31번 하면 음수가 되고, 32번하면 0이 되어 버립니다. "경고! 경고! 오버플로어 발생!" 이런 거죠, 뭐.
그리고 자료형의 범위를 출력할 때 따로 음수를 계산하지 않고 비트 연산자 '~'를 사용했습니다. 오버플로어가 된 상태를 보면, 음수입니다. 그것도 최소값이죠. 최대값에서 1을 더하면 최소값, 최소값에서 1을 빼면 최대값이 됩니다.
시계의 분침을 보면 59분에서 1분이 지나면 0분이 되죠. 만약 시계를 거꾸로 돌린다면 0분에서 59분이 되겠죠? 같은 원리입니다. 그래서 최소값은 number를 그대로 사용하고 최대값은 거꾸로 돌려 최대값을 표현할 수 있게 한 것입니다.

결과는 위와 같이 나왔습니다. 정확하게 오버플로어에서 멈추고 자료형의 범위도 나왔네요. short, int, long 모두 같은 방법으로 결과를 얻을 수 있습니다. long은 %d를 %ld로 바꿔야 하구요.

이건 unsigned 형의 결과입니다. 최소값이 0이므로 음수가 나와서는 안 되는데 음수가 나오고 최대값도 틀렸습니다. 와우, 머리 아퍼 OTL. 그런데 한 가지 이상한 게 있죠? 코드에서는 분명히...
while(number > 0)
{
number <<= 1;
printf("freq = %d, number = %u \n", freq++, number);
}
이렇게 number가 0보다 작거나 같으면 멈추라고 명시했는데, 결과는 안 멈추고 0에서 멈췄습니다. 말이 안 되죠. 이건 내부적으로는 양수인데 보여준 건 음수로 보여줬다는 걸 의미합니다. 비트로 나타내면,
freq == 31 일 때, 10000000 00000000 00000000 00000000
unsigned 이라면, 저건 양수죠. 원인은 %d 때문이었습니다. unsigned의 %u를 안 쓴거죠. 제가 보는 교재에서는 %u를 조심하라고 나오던데, 반성해야겠습니다. 반성. 반성.

정확한 결과는 이렇습니다. 이제야 제대로 나오네요.
처음 C를 배울 때 비트 연산자란 것이 머리만 아프고 필요 없는 것인 줄 알았는데, 이번의 계기로 완전 중독 될 것 같습니다. 기계어와도 1:1 대칭 되어서 연산 속도도 빠르다네요. 다만, 아쉬운 건 정수 자료형에서만 가능하다는 것입니다. 실수에서는 안 되죠. 그래서 지금 머리가 좀 아픕니다. long double의 범위를 구해야 할텐데요. 에효.
"0x08 과거의 글모음 / 내 머리 속의 노트" 분류의 다른 글
| 블로그(텍스트큐브) 서버를 직접 만들어보기 - OS & Package 설치 | 2011/02/16 |
| C/Linux :: 리눅스에서 파일 덤프... dump.c | 2010/12/05 |
| C/Linux :: ls -l 을 수행하는 ll.c | 2010/10/30 |
| python :: Socket Communication with Thread | 2010/10/10 |
| 리눅스(우분투)에서 부경대학교 무선랜 접속하기 | 2010/07/19 |
float, double 형에서 표현 가능한 수의 범위는 정수형에서처럼 간단한 비트연산만 가지고는 구하기 힘들 것 같네요. IEEE-754 표기법에서 비트들을 어떻게 나누어 실수를 표현하는지 찾아보시면 도움이 될 듯. ^^;
ps. 텍스트큐브 포럼에 글 남기신 거 보다가 들어왔는데 마침 컴공 관련 글이 있어 남겨봅니다. ㅋㅋ
네, 요즘 실수를 어떻게 비트로 표현하는지를 공부하고 있습니다. IEEE-754 표기법에 대해 검색하니 참고문헌들이 많이 나오네요. 고맙습니다.