#include <iostream>
using namespace std;

static const int fix_factor = 4096; // 2의 12승
static const int fix_shift = 12; // 쉬프트 값

int main()
{
 // 부동 -> 고정
 double a = 3.245;
 int fix_a = (int)(a*fix_factor);

 // 정수 -> 고정소수
 int b = 10;
 int fix_b = b << fix_shift;

 // 고정소수 -> 부동소수
 double c = (double)fix_a / fix_factor;

 // 고정소수 -> 정수로
 int d = fix_b >> fix_shift;

 printf(" a(3.245) = %d(0x%8X)\n b(10) = %d(0x%8X)\n c(double) = %f(0x%8X)\n d(고정소수를 정수변환) = %d(0x%8X)\n",a,a,b,b,c,c,d,d);

 // 덧셈, 뺄셈
 int plus = fix_a + fix_b;
 int minus = fix_a - fix_b;

 // 곱셈
 int multi = (fix_a * fix_b) >> fix_shift;

 // 나눗셈
 int div = (fix_a << fix_shift) / fix_b;

 printf("\n고정소수점 %d(%0.3f)와 %d(%d)끼리의 연산\n", fix_a, a, fix_b, b);
 printf("+ : %d, - : %d, * : %d, / : %d\n", plus, minus, multi, div);

 printf("fix_factor 만큼 나누기\n");
 printf("+ : %d, - : %d, * : %d, / : %d\n",
  plus / fix_factor , minus / fix_factor, multi / fix_factor, div / fix_factor);

 printf("fix_shiht 만큼 밀기\n");
 printf("+ : %d, - : %d, * : %d, / : %d\n",
  plus >> fix_shift , minus >> fix_shift, multi >> fix_shift, div >> fix_shift);
}

그러니까 32비트열에
xxxxxxxxxxxx.oooooooooooooooooooo
과 같이 임의 의 소수점을 찍어서 거기에 숫자 넣어서 처음부터 계산하는게 아니고

float 나 double 값을 곱셈해서 쉬프트를 시킨후 계산만 정수 연산부를 사용하는 것임.
대부분 cpu는... 정수 연산이 부동 소수점 연산보다 빠르니.. 이게 좋을꺼 같다.

만약, 아예 비트를 쪼개서 정수부, 소수부로 나누어서 계산하고 싶다면..
typedef unsigned int fint;
typedef unsigned char u8;
typedef unsigned short u16;

#define make_fint(i,f)  (fint)(f | i << 20)   // int를 부동소수점 마냥 쓰기
#define get_int(i)   (fint)(i >> 20)    // 정수부분 가져오기
#define get_float(f)  (fint)((f << 12) >> 12)  // 소수점 아래 부분 가져오기
#define get_upper(a)  (fint)(a >> 20)    // 소수점끼리 연산으로 정수로 올라온 숫자 가져오기

이렇게 하고.. 각각 연산에 적당한 함수를 만들어준뒤, 그 함수를 통해서 연산을 해야 할것이다.
이건.. 좀 빡센듯;;

'C/C++언어' 카테고리의 다른 글

LEX & YACC  (0) 2008.06.07
Lex와 Yacc의 사용법 강좌  (0) 2008.06.07
코드 최적화  (0) 2008.05.09
[알고리즘]고정소수점(fixed point) 연산  (0) 2008.05.09
음 고정소수점 만들기..  (0) 2008.05.09
출처 삶 그리고 깨달음 | 프리맨
원문 http://blog.naver.com/lonekid/60008258279

알다시피 실수를 표현하는 방법에는 부동소수점과 고정소수점 두 가지가 있다.

부동소수점은 일반적으로 C에서 float 이나 double 형으로 표현되는 방식이다. 이에 비해 고정소수점은 정수부와 소수부에 고정 비트수를 할당하여 [n.0 ~ n+1.0) 의 범위를 표현하는 방식이다. 즉 지수승은 표현하지 못하며 소수부에 대해 [0 ~ 1) 의 범위를 표현하는 방식이다. 이런 연유로 인해 고정소수점은 일반적으로 정수와 동일한 비트 표현을 갖기 때문에 정수연산과 동일한 레벨에서 처리할 수 있다.


아무리 FPU가 탑재되어 있다하더라도 정수 연산에 비해 부동소수점 연산은 수십배 이상 느리다. 그렇기 때문에 지수승에 의한 넓은 범위의 수치를 다루는 경우가 아니라면 고정소수점을 사용하는 것이 충분한 가치를 갖는다. 일반적으로 학문적 수준에서의 알고리즘들은 실수 구간의 연속 데이타를 대상으로 하지만 컴퓨터는 기본적으로 양자화된 이산(정수) 데이타를 대상으로 한다. 즉, 컴퓨터에 있어 알고리즘의 최종 결과는 대부분 정수이다. 그렇기 때문에서 알고리즘을 컴퓨터로 구현함에 있어 실수가 아닌 정수를 대상으로 하는 고속화된 이산(정수) 알고리즘들이 고안되는 것이다.


일반적으로 실수 알고리즘들은 [0 ~ 1) 범위의 노말라이즈된 수치로 표현되는 것이 보통이다.

정수부와 소수부에 각각 16비트씩 할당하는 16:16 고정소수점을 생각해보자. 정수부는 -32768 ~ +32767의 범위를 표현할 수 있으며 소수부는 [0 ~ 1) 의 범위를 65536 단계의 해상도(소수점 이하 4~5자리의 정확도)로 표현하게 된다. 즉, 0.1은 6554(65536*0.1), 0.5는 32768(65536*0.5), 0.8은 52429(65536*0.8)로 표현된다. 이렇게 표현되는 고정소수점에 대한 가감승제 연산은 컴퓨터 입장에서 32비트 정수에 대한 가감승제 연산과 동일하다. 다만 16비트 소수부에 대한 자리수만 고려해 주면 된다.


이렇게 표현되는 고정소수점에 대한 수학 클래스를 예시한다.

이 클래스에서는 고정소수점 버전의 삼각함수(Sin, Cos, Tan)를 테이블 방식으로 구현하고 있는데 이해하는데 어려움은 없을 것이다.


김인대



// 16:16 fixed point constant

#define FIXED_PI2       102944      // (3.1415926535 / 2) * 65536

#define FIXED_2PI       411775      // (2 * 3.1415926535) * 65536

#define FIXED_PI        205887      // 3.1415926535 * 65536

#define FIXED_R2D       3754936     // (180 / 3.1415926535) * 65536

#define FIXED_D2R       1144        // (3.1415926535 / 180) * 65536

#define FX_R2D(fxR)     ::MulDiv((fxR), 180 * 65536, FIXED_PI)

#define FX_D2R(fxD)     ::MulDiv((fxD), FIXED_PI, 180 * 65536)

 

#ifndef _countof

#define _countof(a)     (sizeof(a)/sizeof(a[0]))

#endif

 

// 16:16 fixed point

typedef long CFixed;

 

// 16:16 fixed point math class.

class CFxMath

{

public:

    static int ToInt(CFixed fxDeg)      { return fxDeg >> 16; }

    static int Round(CFixed fxDeg)      { return (fxDeg + 32768) >> 16; }

    static double ToDbl(CFixed fxDeg)   { return fxDeg / 65536.0; }

    static CFixed ToFx(int n)           { return n << 16; }

    static CFixed ToFx(double d)        { return CFixed(d * 65536); }

   

    static CFixed FxSin(CFixed fxDeg);

    static CFixed FxCos(CFixed fxDeg)   { return FxSin(fxDeg + 90 * 65536); }   // sin(deg + pi/2)

    static CFixed FxTan(CFixed fxDeg);

 

private:

    enum

    {

        eSinTableResolution = 7     // The resolution(bits) of fraction part.

    };

    static USHORT m_awSinTable[90 * (1 << eSinTableResolution)];    // 0 ~ 89.n degree

    static bool m_bInitSinTable;

    static bool InitSinTable();

};

 

// static

CFixed CFxMath::FxSin(CFixed fxDeg)

{

    // Normalize to -360 ~ +360 degree.

    if (fxDeg <= -360 * 65536 || 360 * 65536 <= fxDeg)

    {

        fxDeg = fxDeg % (360 * 65536);

    }

   

    // Normalize to 0 ~ 360 degree.

    if (fxDeg < 0)

    {

        fxDeg = (360 * 65536) + fxDeg;  // sin(2*pi + n) == sin(n)

    }

   

    // Adjust angle for quadrant.

    int nQuad = fxDeg / (90 * 65536);

    switch (nQuad)

    {

    case 1:     // 90 ~ 180 degree

        fxDeg = (180 * 65536) - fxDeg;

        break;

    case 2:     // 180 ~ 270 degree

        fxDeg = fxDeg - (180 * 65536);  // -sin(fxDeg)

        break;

    case 3:     // 270 ~ 360 degree

        fxDeg = (360 * 65536) - fxDeg;  // -sin(fxDeg)

        break;

    case 0:     // 0 ~ 90 degree

    default:

        fxDeg;

        break;

    }

    ASSERT(0 <= fxDeg && fxDeg <= (90 * 65536));

   

    // Sin table lookup.

    long fxSinValue;

    if (fxDeg == (90 * 65536))

    {

        fxSinValue = 1 * 65536;             // For 90 degree

    }

    else

    {

        int nDegIdx = fxDeg >> (16 - eSinTableResolution);

        fxSinValue = m_awSinTable[nDegIdx]; // For 0 ~ 89.n degree

    }

    return (nQuad < 2) ? fxSinValue : -fxSinValue;  // 16:16 fixed point

}

 

// static

CFixed CFxMath::FxTan(CFixed fxDeg)

{

    CFixed fxCos = FxCos(fxDeg);

    return (fxCos == 0) ? MAXLONG : ::MulDiv(FxSin(fxDeg), 65536, fxCos);

}

 

USHORT CFxMath::m_awSinTable[90 * (1 << eSinTableResolution)];  // 0 ~ 89.n degree

bool CFxMath::m_bInitSinTable = InitSinTable();

 

bool CFxMath::InitSinTable()

{

    const double d2r = 3.1415926535 / 180;

    for (int nDegIdx = 0; nDegIdx < _countof(m_awSinTable); nDegIdx++)

    {

        double dDeg = (double)nDegIdx / (1 << eSinTableResolution);

        double dSin = ::sin(dDeg * d2r);

        m_awSinTable[nDegIdx] = USHORT(dSin * 65536 + 0.5);

    }

    return true;

}

'C/C++언어' 카테고리의 다른 글

고정 소수점 (C++언어 버젼)  (0) 2008.05.09
코드 최적화  (0) 2008.05.09
음 고정소수점 만들기..  (0) 2008.05.09
고정 소수점  (0) 2008.05.09
각 언어별 3중 포인터  (0) 2008.05.06

#include <iostream>

using namespace std;

typedef unsigned int fint;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

#define make_fint(i,f)  (fint)(f | i << 20)   // int를 부동소수점 마냥 쓰기
#define get_int(i)   (fint)(i >> 20)    // 정수부분 가져오기
#define get_float(f)  (fint)((f << 12) >> 12)  // 소수점 아래 부분 가져오기
#define get_upper(a)  (fint)(a >> 20)    // 소수점끼리 연산으로 정수로 올라온 숫자 가져오기

fint fint_plus(fint a, fint b)
{
 int ai, af;
 int bi, bf;
 int upper;
 int ri, rf;

 ai = get_int(a);
 af = get_float(a);

 bi = get_int(b);
 bf = get_float(b);

 rf = af + bf;
 upper = get_upper(rf);
 ri = ai + bi + upper;
 
 return make_fint(ri,rf);
}


fint fint_sub(fint a, fint b)
{
 int ai, af;
 int bi, bf;
 int upper;
 int ri, rf;

 ai = get_int(a) - 1;
 af = get_float(a);

 bi = get_int(b);
 bf = get_float(b);

 rf = (af + (1<<21)) - bf;
 upper = get_upper(rf);
 ri = (ai + upper) - bi;
 
 return make_fint(ri,rf);
}

int main()
{
 int a = 0xff0;
 int b = 0xf5ff0;
 fint c = make_fint(a,b);
 
 printf("%x\n", c);

 fint d = get_int(c);
 fint e = get_float(c);
 printf("int : %x,    float : %x\n", d, e);
 
 fint f,g;
 f = make_fint(5,5000);
 g = make_fint(4,9920);

 fint sum = fint_plus(f,g);
 fint sub = fint_sub(f,g);
 printf("a = %d.%d,   b = %d.%d\n",
  get_int(f), get_float(f), get_int(g),get_float(g));
 printf("plus %d.%d, sub %d.%d\n",
  get_int(sum), get_float(sum), get_int(sub),get_float(sub));
/*
 5.005
 -4.992
 --------
    008 + 005
 013

  5.992
 -6.001
 ---------
 -1.991
 */
}

// 하루히 와핑 소스
/*
// 바꾼 이미지 복구? 음.. 제거쪽이 해석이 맞을지도
//v3.0
function MM_swapImgRestore()
{
 var i,x,a=document.MM_sr;
 for(i=0; a && i<a.length&&(x=a[i]) && x.oSrc;i++)
  x.src=x.oSrc;
}

// 이미지들을 먼저 읽어오기
//v3.0
function MM_preloadImages()
{
 var d=document;
 
 if(d.images)
 {
  if(!d.MM_p)
   d.MM_p = new Array();

  var i, j = d.MM_p.length, a=MM_preloadImages.arguments;
  for(i=0; i < a.length; i++)
   if (a[i].indexOf("#") != 0)
   {
    d.MM_p[j]=new Image;
    d.MM_p[j++].src=a[i];
   }
 }
}

// 오브젝트 찾기 (즉 케릭터가 주목하는 방향 좌표)
//v4.01
function MM_findObj(n, d)
{
 var p,i,x; 

 if(!d)
  d=document;

 if((p=n.indexOf("?")) > 0 && parent.frames.length)
 {
  d=parent.frames[n.substring(p+1)].document;
  n=n.substring(0,p);
 }

 if(!(x=d[n]) && d.all)
  x=d.all[n];

 for (i=0; !x && i<d.forms.length; i++)
  x=d.forms[i][n];

 for(i=0; !x && d.layers && i<d.layers.length; i++)
  x=MM_findObj(n,d.layers[i].document);

 if(!x && d.getElementById)
  x=d.getElementById(n);
 return x;
}

// 이미지 바꾸기
//v3.0
function MM_swapImage()
{
 var i, j=0, x, a=MM_swapImage.arguments;

 document.MM_sr = new Array;

 for(i=0; i < (a.length-2); i+=3)
  if ((x = MM_findObj(a[i])) !=null)
  {
   document.MM_sr[j++]=x;

   if(!x.oSrc)
    x.oSrc=x.src;

   x.src=a[i+2];
  }
}
*/

'C/C++언어' 카테고리의 다른 글

코드 최적화  (0) 2008.05.09
[알고리즘]고정소수점(fixed point) 연산  (0) 2008.05.09
고정 소수점  (0) 2008.05.09
각 언어별 3중 포인터  (0) 2008.05.06
쉬프트 연산과 곱셈  (0) 2008.03.26

최근 하고 있는 것이 여러 뻘짓이다 보니 본이 아니게 3중 포인터를 쓰게 되더군요.

대략… 3차원 표현 이라던가…

2차원의 영역중, 각 픽셀의 갖고있는 간단한 값을 가져올 때, 안쓸꺼 같던것들이 자주 쓰이더군요.

일단 예제.. 여기서 예제는 int a[10][20][30] 과 같은 역활을 하는 동적 메모리 할당을 해봅니다.

일단 C언어부터…

// 만들때

int ***ptr;
ptr = (int ***)malloc(sizeof(int **) * 10);

for(i=0; i < 10; ++i)
{
    ptr[i] = (int **)malloc(sizeof(int *) * 20);   

    for(j=0; j < 20; ++j)
        ptr[i][j] = (int *)malloc(sizeof(int) * 30);
}

// 해제할때
for(i=0; i < 10; ++i)
{
    for(j=0; j < 20; ++j)
        free(ptr[i][j]);

    free(ptr[i]);
}

free(ptr);

그리고 C++, C++ 답게 new와 delete 명령어를 써서 (물론 위의 C방법으로 해도 상관없습니다.)

 

 //<!----- 3차원 배열 예제 -----//
//배열을 X,Y,Z에 각각 10,20,30 식 할당.
#define ARRAY_X  (10)
#define ARRAY_Y  (20)
#define ARRAY_Z  (30)
void main()
{
     //선언
     int ***ptr;
     //할당
     ptr = new int**[ARRAY_X];    //X차원 선언
     for(int i=0; i<ARRAY_X; ++i) {
         ptr[i] = new int *[ARRAY_Y];  //Y차원 선언
     } 
     for(int i=0; i<ARRAY_X; ++i){
         for(int j=0; j<ARRAY_Y; ++j) {
             ptr[i][j] = new int[ARRAY_Z]; //Z차원 선언
   
             for(int k=0; k<ARRAY_Z; ++k){
            //값을 씀.
                 ptr[i][j][k] = i*j*k;
             }
         }
    }
    // 해제할때, 역으로 Z부터 해제함.
    for(int i=0; i<ARRAY_X; ++i) {
        for(int j=0; j<ARRAY_Y; ++j) {
            for(int k=0; k<ARRAY_Z; ++k){
                printf("ptr[%d][%d][%d] = %d\n", i, j, k, ptr[i][j][k]);
            }
           delete [] ptr[i][j];  //Z차원 해제
        }
        printf("\n");
    }
    for(int i=0; i<ARRAY_X; ++i) {
        delete [] ptr[i];    //Y차원 해제
    }
    delete []ptr;      //X차원 해제
    return 0;
}

 마지막으로 Java ...
Java의 경우.. 포인터가 없죠;;
Java의 메모리는 C언어처럼 직접 건들이는 구조가 아니고,
물리적 메모리 공간과 별도로 여길 관리하는 메모리 관리자가 있습니다..(Virtual Machine(이하 VM)안에)
여기의 메모리 관리자가 알아서 할당합니다. (OS에서 자원 관리 하듯이라 생각하셔도 됩니다.)

즉 int a[10] 이라 하면, 내부적으로는 C언어처럼 malloc(sizeof(int) * 10)이 일어난다는거죠.
C언어적인 문법상으로 보면 그냥 정적 배열처럼 보이지만... 내부적으론 동적 배열 처리한다고 보시면 됩니다.

해제는.. 간단하게 null 해주면 VM의 메모리 관리자가 해당 영역을 없는 셈 칩니다.
(파일을 지울때 앞글자만 지워주고 없는셈 치는것과 같은 이치입니다)

완전히 메모리 상에서 지우고 싶을땐 가비지 컬렉터를 강제로 실행시켜줘야 하지만..
굳이 할필요는 없습니다.
만약 VM이 메모리 할당이 일어날때 더 이상 메모리가 없다면,
현재 사용되지 않는 메모리 할당자들,
즉 위의 null 처럼 되어있는것.. 이라던가, 클래스에서 나와 더이상 사용하지 않는 변수들 같은것들을
찾아 지워준뒤, Compaction등이 일어납니다. 그리고 빈곳에 메모리를 할당하죠.
개념은 이정도고 실제 작동원리나 자세한건 Java책을 참고하시기 바랍니다.

// 만들때
int ptr[][][] = null;
ptr = new int[10][20][30];

// 해제할때
ptr = null;
System.gc(); // 선택사항

전세계에서 제일 많이 사용하는 언어는 자바란 이유가.. 이런 편리함 때문일껍니다... T_T

C언어의 모토(motto)는
-> 어떤 머신이든 제어하는 언어를 만들자.
이지만,

Java의 모토(motto)는
-> 코딩은 1번, 코딩된 소스를 변형없이 모든 머신에서 돌아가는 프로그램을 만들자
라고 합니다.

실제... C언어는 ARM 계열이나. 리눅스의 GCC, MS의 Visual C++ ... 미묘하게 다릅니다.
int 의 경우만해도 보통은 4byte로 알고있지만, 사실은 해당 머신에서 숫자를 표현하기 적당한 공간을 뜻합니다.
무슨말이냐면
간단한 휴대폰의 경우 int의 할당은 2byte or 1byte 만 할당될수도 있고, PC에선 4byte, 서버나 과학용 컴퓨터에선 8byte 이상을 할당할수 있다는 얘기죠.
그게 무슨 대수냐..... 하실지도 모르지만.. 게임 만들다보면.. 이것까지 제어하는 부분까지.. orz

Java는.. int 는 4byte 라고 정해져 있습니다. 이건 어떤 머신이든 VM이 있다면 무족건 4byte로 쳐줍니다.

'C/C++언어' 카테고리의 다른 글

음 고정소수점 만들기..  (0) 2008.05.09
고정 소수점  (0) 2008.05.09
쉬프트 연산과 곱셈  (0) 2008.03.26
[리눅스프로그래밍] makefile  (1) 2008.03.07
ASSERT(), VERIFY(), TRACE()  (0) 2008.03.04

실전 STL 플밍.. 소스 참고..

+ Recent posts