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의 범위를 구해야 할텐데요. 에효.


Similar Posts

  • RSS 피드를 직접 만들어 보자. Feed43 활용…

    PC사랑 홈페이지의 포인트경매를 아시나요? 경매방식이 재미있고 제품들도 쓸만해서 제가 좋아하는 컨텐츠입니다. 예전에는 매일 홈페이지에 들어가서 경매가 어떻게 되어가는지 확인했지만, 이제는 RSS로 받아서 쉽게 확인하고 있습니다. Feed43을 이용하지요. Feed43에 대해 소개한 글들을 보면 어떻게 RSS를 만드는지 자세하게 나와있지 않아 참 힘들었습니다. 이번도 2시간의 삽질을 거쳐 간신히 RSS 피드를 만들었습니다. 2시간동안 삽질했더니 이제 어느정도 알겠더군요. 그래서 제가…

  • imagEmail, 간략한 기획

    비주얼 베이직으로 만들었던 hisAlpha Image를 C 언어를 이용하여 리눅스용으로 다시 만들려고 합니다.  리눅스용이라고는 하나, 윈도우나 OS X용으로도 쉽게 포팅될 듯합니다. hiaAlpha Image는 일종의 프로토타입인 것이죠. 사실, 강분도 님의 권유가 아니었으면 그냥 묻혔을겁니다. ㅋ 아래는 간략한 기획입니다. 기능 이메일 주소를 이미지로 만듬. 15종의 메일서버 지원. 개발환경 환경: 리눅스 (Ubuntu 8.10, i386) 언어 및 툴킷 : C,…

  • 알고리즘 :: 입력된 수가 소수인지 확인하자.

    입력된 양의 정수가 소수인지 아닌지를 확인해보려 합니다. 우선, 소수가 무엇인지부터 알아야겠죠? 소수란 1과 자기 자신 외의 약수를 가지지 않는 1보다 큰 자연수를 말합니다. 그렇다면 알고리즘도 이러한 소수의 특징을 이용하여 구현할 수 있습니다. 입력된 값이 1보다 크고 자기 자신보다 작은 자연수에 의해 나누어 떨어지는지만 확인하면 되죠. 여기서 반복문을 사용해야 한다는 것을 짐작하시겠죠? 이제 소스를 보겠습니다. 자연수에…

  • C :: gcc 컴파일러에서 자료형의 크기는 얼마?

    C언어로 sizeof() 함수를 이용하여 구해봤습니다. 환경은 32 bit 입니다. 대체로 Visual C++의 자료형 크기와 동일한 값이 나옵니다. 다만, long double 형의 크기가 더 크게 나왔습니다. Visual C++에서는 double와 동일하게(실제로는 지원하지 않는거죠) 8 byte 이지만, Monodevelop에서는 12 byte 입니다. 터보 C가 10 byte 인데, 범위가 3.4*10-4932 ~ 1.1*104932 이라고 하네요. 우와! 그럼, 12 byte 이면? 시간…

  • 알고리즘 :: XOR 스왑 알고리즘의 문제점이 무엇일까?

    지난 글에서 XOR 연산을 이용한 스왑 알고리즘을 소개했습니다. 그리고 이 알고리즘의 문제점에 대해서도 언급했는데, 그때는 제가 그 문제점을 이해하지 못해서 자세히는 못 다루었네요. 그때 소개한 문제점을 다시 보겠습니다. 코드를 이해하기 어렵다. 두 변수의 메모리 위치가 동일할 때 동작하지 않는다. 제가 이해하지 못한 것이 2번이었죠. 두 변수의 메모리 위치가 동일하다는 말은 의미 그대로입니다. 아래 예를 보겠습니다….

  • C :: multiple definition 에러

    카드 게임을 구현하는 코드를 짰는데, 컴파일해보니 이런 메시지가 나왔습니다. 0 errors, 0 warnings 아주 반가운 메시지죠. 하지만 실행이 되질 않더군요. 그래서 메시지를 자세히 보니 multiple definition of ‘strSuit’ multiple definition of ‘strFace’ 라고 나와 있는 겁니다. 해석하면 strSuit, strFace 변수의 정의가 중복되었다는 건데, 어디서 중복되었는지를 찾질 못하고 이틀을 헤매었습니다. 원인도 모른 채 이렇게 수정해보고 저렇게…

0 Comments

  1. 네, 요즘 실수를 어떻게 비트로 표현하는지를 공부하고 있습니다. IEEE-754 표기법에 대해 검색하니 참고문헌들이 많이 나오네요. 고맙습니다.

  2. float, double 형에서 표현 가능한 수의 범위는 정수형에서처럼 간단한 비트연산만 가지고는 구하기 힘들 것 같네요. IEEE-754 표기법에서 비트들을 어떻게 나누어 실수를 표현하는지 찾아보시면 도움이 될 듯. ^^;

    ps. 텍스트큐브 포럼에 글 남기신 거 보다가 들어왔는데 마침 컴공 관련 글이 있어 남겨봅니다. ㅋㅋ

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다