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

  • 알고리즘 :: XOR 연산을 이용하여 스왑 알고리즘을 최적화하자.

    한동훈 님의 「프로그래밍 스타일」이라는 글을 읽다가 스왑(Swap) 알고리즘에 대한 코드가 있어서 소개합니다. 아시는 분들도 많겠지만, 모르는 분들도 많을거라 생각되네요. 흔히 두 값을 맞바꿀 때 이런 알고리즘을 사용합니다. 변수 temp를 하나 더 선언해서 중간매개체로 사용하죠. 이 때문에 4byte의 메모리를 더 차지합니다. 하지만 아래에 소개할 알고리즘은 추가적인 메모리가 필요 없습니다. 전 이 알고리즘을 처음 보고 와우! 하고…

  • C :: 0xE0 == 224 ?

    어느 한 분이 게시판에 질문을 올리셨습니다. 소코반 소스중에 일부분입니다. int ch; ch = getch(); //키 입력 if( ch==0xE0 ) { //실행 } 0xE0 은 십진수로 224입니다. 그러면 ch==224 랑 같으면 실행 된다는 말인가요 ㅡ.ㅡ? 『혼자 연구하는 C/C++』에 나오는 한 예제에 대한 질문이었습니다. C에서는 문자형으로 char가 사용됩니다. char는 1byte 자료형으로 -128~127의 값을 가집니다. 그럼 여기서부터 문제가…

  • C :: [열혈강의 C 프로그래밍] p.115 char_add.c

    tothefelix 님의 블로그에서 아래의 코드를 가져왔습니다. 언뜻 보면 정상적인 코드인 것 같으나, 유심히 보면 자료형이 잘못된 것을 알 수 있습니다. 1바이트의 char 형 변수에 4바이트의 int 형 값을 넣는 오류입니다. 명백히 코드 상의 오류지요. 정말 열혈강의에 저런 코드가 예문으로 나와 있다면 무척 실망입니다. 역시 국내 C 레퍼런스로는 김상형 님의 “혼자 연구하는 C/C++“가 최고의 레퍼런스가 아닌가…

  • Feed43 활용. 게시판을 RSS로 구독하기

    이전 글에서 소개한 바와 같이 Feed43의 유용함은 정말 뛰어납니다. Feed43과 같은 서비스를 적극적으로 활용하면 RSS로 많은 정보를 간편하게 취할 수 있고 분류도 할 수 있습니다. 이번에는 Feed43으로 게시판을 RSS로 구독하는 방법을 알아 보겠습니다. 간단한 코드 한 줄만 이용하면 되므로 어려운 내용은 아닙니다. 위 그림같은 게시판이 있습니다. 게시판의 구성은 번호, 제목, 이름, 날짜, 조회수, 첨부파일 링크…

  • imagEmail, GUI 구현

    GTK+와 Glade 3로 구현한 GUI입니다. 이제 여기에 C 코드로 알고리즘만 얹어 놓으면 됩니다. windowMain windowMain은 이름 그대로 메인 화면입니다. 오른쪽의 드롭다운 버튼으로 이메일의 서버종류를 선택할 수 있습니다. 우측 상단의 x 버튼으로 프로그램을 종료합니다. dialogSave dialogSave는 파일을 저장할 때 나오는 대화상자입니다. 아직 100% 구현되지 않았는데, 다 구현되면 “저장”, “취소” 버튼 위에 이메일 이미지가 어떻게 나오는지 보여줄…

  • C :: 실수(Float)를 엿보려면 컴퓨터를 속여라.

    이전에 비트 연산을 통해서 정수의 내부 비트를 엿보는 코드를 짰었습니다. 그러고부터 5주가 지난 지금에서야 실수의 내부 비트를 볼 수 있는 코드를 완성했네요. 딱 코드 한 줄만 추가하면 되는 문제였지만, 포인터에 대한 이해가 바탕이 되어야 했기 때문에 5주가 걸렸습니다. 우선 코드부터 보겠습니다. 지난 글과 코드가 많이 달라보이는 듯 하지만 실제로는 출력부를 함수로 끄집어내고, 핵심 코드 한…

0 Comments

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

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

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

답글 남기기

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