우선 다음 소스는 컴파일하는데는 아무 문제가 없지만 실행 결과는 전혀 엉뚱하다.

printf 함수에 사용된 %lld 포맷에 문제가 있기 때문이다.

 

/*
 * Filename: testLongLong0.c
 *
 * Compile: gcc -o testLongLong0 testLongLong0.c
 *   or
 * Compile: cl testLongLong0.c
 */

#include <stdio.h>

int main()
{
    printf("Maximum long long value is %40lld\n", 9223372036854775807LL);
    printf("Maximum long long value is %40llu\n", 9223372036854775807ULL);
    printf("Maximum long long value is %40lld\n", 9223372036854775808LL);
    printf("Maximum long long value is %40llu\n", 9223372036854775808ULL);

    return 0;
}

 

우선 다음은 32비트 윈도우 XP의 명령창에서 Visual C++ 2010 의 명령줄 컴파일러 cl 로 컴파일하여 실행한 경우이다.

컴파일> cl testLongLong0.c
Microsoft (R) 32비트 C/C++ 최적화 컴파일러 버전 16.00.40219.01(80x86)
Copyright (c) Microsoft Corporation. 모든 권리 보유.

testLongLong0.c
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:testLongLong0.exe
testLongLong0.obj

실행> testLongLong0
Maximum long long value is                      9223372036854775807
Maximum long long value is                      9223372036854775807
Maximum long long value is                     -9223372036854775808
Maximum long long value is                      9223372036854775808

 

 

그리고 다읍은 32비트 윈도우 XP의 명령창에서 MinGW 의 gcc(버잔 4.7.3) 로 컴파일하여 실행한 경우이다.

컴파일> gcc -o testLongLong0 testLongLong0.c
testLongLong0.c: In function 'main':
testLongLong0.c:15:51: warning: integer constant is so large that it is unsigned
 [enabled by default]
testLongLong0.c:15:5: warning: this decimal constant is unsigned only in ISO C90
 [enabled by default]

실행> testLongLong0
Maximum long long value is                                       -1
Maximum long long value is                               4294967295
Maximum long long value is                                        0
Maximum long long value is                                        0

 

 

* ISO C99 표준에 따라 64비트 정수를 printf 함수로 출력할 때 inttypes.h 헤터파일을 인클루드하고 PRId64, PRIu64, PRIx64, PRIX64 등을 사용한다. 예를 들면,

        printf("My value is %10"PRId64"\n", some_64_bit_expression);

이다. scanf 함수로 64비트 정수를 입력받을 때는 SCNd64, SCNu64, SCNx64, SCNX64 등을 사용한다.

아래의 소스는 gcc 로 컴파일할 때 경고는 있지만 실행시 출력은 정상이다. 

/*
 * Filename: testLongLong1.c
 *
 * Compile: gcc -o testLongLong1 testLongLong1.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main()
{
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775807L);
    printf("       uint64 value is %40" PRIu64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
Maximum int64 value is                      9223372036854775807
Maximum int64 value is                         7fffffffffffffff
Maximum int64 value is                         7FFFFFFFFFFFFFFF
       uint64 value is                      9223372036854775807
Maximum int64 value is                     -9223372036854775808
Maximum int64 value is                         8000000000000000
Maximum int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |7fffffffffffffff                        |
Maximum int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

* Visual C++ 2010 에서는 64비트 정수를 printf 함수로 출력하기 위해 PRId64, PRIu64, PRIx64, PRIX64 등을 사용하면 inttypes.h 헤더 파일을 찾을 수 없다는 에러가 난다. 이 에러를 해결하기 위해 http://msinttypes.googlecode.com/svn/trunk/inttypes.h 를 인클루드하였다.

아래의 소스는 cl 로 경고 없이 컴파일도 잘 되고 실행시 출력도 정상이다. 

/*
 * Filename: testLongLong.c
 *
 * Compile: cl testLongLong.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include <stdio.h>
#include "inttypes.h"

int main()
{
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775807L);
    printf("       uint64 value is %40" PRIu64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
Maximum int64 value is                      9223372036854775807
Maximum int64 value is                         7fffffffffffffff
Maximum int64 value is                         7FFFFFFFFFFFFFFF
       uint64 value is                      9223372036854775807
Maximum int64 value is                     -9223372036854775808
Maximum int64 value is                         8000000000000000
Maximum int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |7fffffffffffffff                        |
Maximum int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

* 다음 소스는 gcc 또는 cl  어느 것으로도 컴파일되고 실행결과도 같지만, gcc 로 컴파일 할 때는 인크루드 부분을

        #include <inttypes.h>

로 수정해야 한다. gcc 는 4.7.x 이상이면 컴파일되고, Visual C++ 는 2008 이상이면 컴파일된다.

그대신 Visual C++ 2008 에는 헤더파일 stdint.h 가 빠져 있으므로 http://msinttypes.googlecode.com/svn/trunk/stdint.h  에서 내려받으면 된다. Visual C++ 2010 에는 이 헤더파일이 이미 있으므로 상관 없다.

 

* gcc 로 컴파일하기:

    gcc -std=c99 -o testLongLong2 testLong2.c

또는

    gcc -o testLongLong2 testLong2.c

* cl 로 컴파일하기:

    cl testLong2.c

 

/*
 * Filename: testLongLong2.c
 *
 * Compile: gcc -o testLongLong2 testLongLong2.c
 *     or
 * Compile:cl testLongLong2.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://msinttypes.googlecode.com/svn/trunk/stdint.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include "stdint.h"      //  #include <inttypes.h>  for gcc or Visual C++ 2010
#include "inttypes.h"    //  #include <inttypes.h>  for gcc

int main()
{
    printf(" INT64_MAX = %30" PRId64 "\n", INT64_MAX);
    printf(" INT64_MAX = %30" PRIx64 "\n", INT64_MAX);
    printf("UINT64_MAX = %30" PRIu64 "\n", UINT64_MAX);
    printf("UINT64_MAX = %30" PRIx64 "\n", UINT64_MAX);
    printf("\n");

    printf("Maximum  int64 value is %40" PRId64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRIx64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRIX64 "\n", 9223372036854775807LL);
    printf("        uint64 value is %40" PRIu64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRId64 "\n", 9223372036854775808ULL);
    printf("Maximum  int64 value is %40" PRIx64 "\n", 9223372036854775808ULL);
    printf("Maximum  int64 value is %40" PRIX64 "\n", 9223372036854775808ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808ULL);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum  int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
 INT64_MAX =            9223372036854775807
 INT64_MAX =               7fffffffffffffff
UINT64_MAX =           18446744073709551615
UINT64_MAX =               ffffffffffffffff

Maximum  int64 value is                      9223372036854775807
Maximum  int64 value is                         7fffffffffffffff
Maximum  int64 value is                         7FFFFFFFFFFFFFFF
        uint64 value is                      9223372036854775807
Maximum  int64 value is                     -9223372036854775808
Maximum  int64 value is                         8000000000000000
Maximum  int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum  int64 value is |9223372036854775807                     |
Maximum  int64 value is |9223372036854775807                     |
Maximum  int64 value is |7fffffffffffffff                        |
Maximum  int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

 

 

Posted by Scripter
,

C 언어 프로그래밍에서 까다로운 부분 중의 하나는 획득했던(할당받았던) 메모리를 여하히 해제하느냐이다. 프로그램밍의 사소한 오류로 메모리 부족 현상이 쉽게 일어나기 때문이다.

자바 언어, 파이썬 언어, C# 언어 등은 자동으로 쓰레기 수집(garbage collection)이 이루어지므로 거의 신경쓰지 않아도 되지만, C 언어는 소스 작성하는 프로그래머가 직접해야 한다.

오래 전(10여년 전)에 Hans Boehm 가 만들었던 C/C++ 언어용 쓰레기 수집기(Boehm-Demers-Weiser conservative garbage collector, 줄여사 BoehmGC 러고 부름)를 이용하여 컴파일되고 실행되는 소스이다. 이 쓰레기 수집기를 쓰면, 메모리 해제(free)를 프로그래머가 신경쓰지 않아도 된다. 그렇게 하기 위해서는 헤더 파일 추가 구문

              #include "gc.h"     또는      #include "gc/gc.h"

가 있어야 하고,  함수 malloc(크기) 대신에 매크로 GC_MALLOC(크기) 를, 함수 realloc(포인터, 크기) 대신에 매크로 GC_REALLOC(포인터, 크기) 를 사용해야 한다. 좀 더 좋은 성능을 위해서는 GC_MALLOC_ATOMIC(크기) 과 GC_enable_incremental() 을 사용하기도 한다. GC_MALLOC_ATOMIC 은 포인터를 전혀 갖지 않은 객체에 대하여만 적용된다. 



MinGW 의 gcc 나 Visual C++ 2010 용으로 동작하는지는 아직 확인 되지는 않았으나, Cygwin에는 Hans Boehm 의 쓰레기 수집기가 이미 설치되어 있어서, Cygwin 의  gcc 4.5.3 으로 컴파일할 수 있었다.

 

/*
 * Filename: testGC_01.c 
 *
 *           Test a garbage collection for C language.
 *
 * Compile: gcc -o testGC_01 testGC_01.c -lgc
 *
 * Execute: ./testGC_01
 *
 * See: http://www.hpl.hp.com/personal/Hans_Boehm/gc/simple_example.html
 */


#include "gc.h"
#include <assert.h>
#include <stdio.h>

int main()
{
    int i;

    GC_INIT(); /* Optional on Linux/X86; see below.  */
    for (i = 0; i < 10000000; ++i)
    {
        int **p = (int **) GC_MALLOC(sizeof(int *));
        int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
        assert(*p == 0);
        *p = (int *) GC_REALLOC(q, 2 * sizeof(int));
        if (i % 100000 == 0)
            printf("Heap size = %d\n", GC_get_heap_size());
    }

    return 0;
}

 

 

실행 결과:
Heap size = 65536
Heap size = 131072
.................
.................
.................

 

 

* 단일 쓰레드에서 쓰레기 수집  벤치마크 테스트 (파일명: GCBench.c)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#ifdef GC
#  include "gc.h"
#endif

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("Creating %d trees of depth %d\n", iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\tTop down construction took %d msec\n",
               elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\tBottom up construction took %d msec\n",
               elapsedTime(tFinish - tStart));

}

int main() {
        Node    root;
        Node    longLivedTree;
        Node    tempTree;
        long    tStart, tFinish;
        long    tElapsed;
   int i, d;
 double  *array;

#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes.\n\n",
               2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
               sizeof(double) * kArraySize);
        printf(" Stretching memory with a binary tree of depth %d\n",
               kStretchTreeDepth);
        PrintDiagnostics();
# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
       
        // Stretch the memory space quickly
        tempTree = MakeTree(kStretchTreeDepth);
# ifndef GC
          destroy_Node(tempTree);
# endif
        tempTree = 0;

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }
        PrintDiagnostics();

        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }

        if (longLivedTree == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o GCBench GCBench.c -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 378 msec
        Bottom up construction took 374 msec
Creating 8256 trees of depth 6
        Top down construction took 379 msec
        Bottom up construction took 357 msec
Creating 2052 trees of depth 8
        Top down construction took 379 msec
        Bottom up construction took 354 msec
Creating 512 trees of depth 10
        Top down construction took 383 msec
        Bottom up construction took 356 msec
Creating 128 trees of depth 12
        Top down construction took 382 msec
        Bottom up construction took 363 msec
Creating 32 trees of depth 14
        Top down construction took 387 msec
        Bottom up construction took 381 msec
Creating 8 trees of depth 16
        Top down construction took 396 msec
        Bottom up construction took 400 msec
Completed in 5525 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o GCBench GCBench.c -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 44 msec
        Bottom up construction took 37 msec
Creating 8256 trees of depth 6
        Top down construction took 43 msec
        Bottom up construction took 39 msec
Creating 2052 trees of depth 8
        Top down construction took 38 msec
        Bottom up construction took 38 msec
Creating 512 trees of depth 10
        Top down construction took 38 msec
        Bottom up construction took 38 msec
Creating 128 trees of depth 12
        Top down construction took 44 msec
        Bottom up construction took 38 msec
Creating 32 trees of depth 14
        Top down construction took 38 msec
        Bottom up construction took 39 msec
Creating 8 trees of depth 16
        Top down construction took 38 msec
        Bottom up construction took 52 msec
Completed in 640 msec
Completed 25 collections
Heap size is 28975104

 

* 다중 쓰레드에서 쓰레기 수집  벤치마크 테스트 (파일명: MT_GCBench.c)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
// Adapted to run NTHREADS client threads concurrently.  Each
// thread executes the original benchmark.  12 June 2000  by Hans Boehm.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>

#ifdef GC
#  ifndef LINUX_THREADS
#     define LINUX_THREADS
#  endif
#  ifndef _REENTRANT
#     define _REENTRANT
#  endif
#  ifdef LOCAL
#    define GC_REDIRECT_TO_LOCAL
#    include "gc_local_alloc.h"
#  endif
#  include "gc.h"
#endif


#ifndef NTHREADS
#   define NTHREADS 1
#endif

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("0x%x: Creating %d trees of depth %d\n", pthread_self(), iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Top down construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Bottom up construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));

}

void * run_one_test(void * arg) {
 int d;
        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }
}

int main() {
        Node    root;
        Node    longLivedTree;
        Node    tempTree;
        long    tStart, tFinish;
        long    tElapsed;
   int i;
 double  *array;

#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
#       if defined(GC) && defined(LOCAL)
   GC_thr_init();
#   endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes.\n\n",
               2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
               sizeof(double) * kArraySize);
        printf(" Stretching memory with a binary tree of depth %d\n",
               kStretchTreeDepth);
        PrintDiagnostics();
# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
       
        // Stretch the memory space quickly
        tempTree = MakeTree(kStretchTreeDepth);
# ifndef GC
          destroy_Node(tempTree);
# endif
        tempTree = 0;

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }

        {
   pthread_t thread[NTHREADS];
   for (i = 1; i < NTHREADS; ++i) {
         int code;

     if ((code = pthread_create(thread+i, 0, run_one_test, 0)) != 0) {
           fprintf(stderr, "Thread creation failed %u\n", code);
       exit(1);
     }
   }
   /* We use the main thread to run one test.  This allows */
   /* profiling to work, for example.    */
   run_one_test(0);
   for (i = 1; i < NTHREADS; ++i) {
         int code;
     if ((code = pthread_join(thread[i], 0)) != 0) {
         fprintf(stderr, "Thread join failed %u\n", code);
           }
    }
        }
        PrintDiagnostics();

        if (longLivedTree == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o MT_GCBench MT_GCBench.c -lgc

* 실행하기
$ ./MT_GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 379 msec
        0x4b0038: Bottom up construction took 353 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 380 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 379 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 382 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 386 msec
        0x4b0038: Bottom up construction took 361 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 383 msec
        0x4b0038: Bottom up construction took 360 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 389 msec
        0x4b0038: Bottom up construction took 373 msec
Completed in 5423 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o MT_GCBench MT_GCBench.c -lgc

* 실행하기
$ ./MT_GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 52 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 44 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 44 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 51 msec
Completed in 651 msec
Completed 25 collections
Heap size is 28975104

 

 

* 다중 쓰레드에서 쓰레기 수집  벤치마크 테스트 2 (파일명: MT_GCBench2.c)

// This is version 2 of the multithreaded GC Bench.
// Heap expansion is handled differently from version 1, in an attempt
// to make scalability measurements more meaningful.  The version with
// N threads now immediately expands the heap to N*32MB.
//
// To run this with BDWGC versions 6 and later with thread local allocation,
// define GC and LOCAL.  Without thread-local allocation, define just GC.
// To run it with the University of Tokyo scalable GC,
// define SGC.  To run it with malloc and explicit deallocation, define
// none of these.  (This should also work for Hoard.)
//
// Note that defining GC or SGC removes the explicit deallocation passes,
// which seems fair.
//
// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
// Adapted to run NTHREADS client threads concurrently.  Each
// thread executes the original benchmark.  12 June 2000  by Hans Boehm.
// Changed heap expansion rule, and made the number of threads run-time
// configurable.  25 Oct 2000 by Hans Boehm.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we were aware at the time.
//      It still doesn't seem too bad for something this small.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  This versions of the benchmark tries
//      to preallocate a sufficiently large heap that expansion should not be
//      needed.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.
//
//      Since this benchmark has recently been more widely used, some
//      anomalous behavious has been uncovered.  The user should be aware
//      of this:
//      1) Nearly all objects are of the same size.  This benchmark is
//         not useful for analyzing fragmentation behavior.  It is unclear
//         whether this is an issue for well-designed allocators.
//      2) Unless HOLES is defined, it tends to drop consecutively allocated
//         memory at the same time.  Many real applications do exhibit this
//         phenomenon, but probably not to this extent.  (Defining HOLES tends
//         to move the benchmark to the opposite extreme.)
//      3) It appears harder to predict object lifetimes than for most real
//         Java programs (see T. Harris, "Dynamic adptive pre-tenuring",
//         ISMM '00).

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>

#ifdef GC
#  ifndef LINUX_THREADS
#     define LINUX_THREADS
#  endif
#  ifndef _REENTRANT
#     define _REENTRANT
#  endif
#  ifdef LOCAL
#    define GC_REDIRECT_TO_LOCAL
#    include "gc_local_alloc.h"
#  endif
#  include "gc.h"
#endif
#ifdef SGC
#  include "sgc.h"
#  define GC
#  define pthread_create GC_pthread_create
#  define pthread_join GC_pthread_join
#endif

#define MAX_NTHREADS 1024

int nthreads = 0;

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("0x%x: Creating %d trees of depth %d\n", pthread_self(), iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Top down construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Bottom up construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));

}

void * run_one_test(void * arg) {
 int d, i;
        Node    longLivedTree;
 double  *array;
 /* size_t initial_bytes = GC_get_total_bytes(); */

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }

        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }
 /* printf("Allocated %ld bytes before start, %ld after\n",
  initial_bytes, GC_get_total_bytes() - initial_bytes); */
        if (longLivedTree->left -> right == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

}

int main(int argc, char **argv) {
        Node    root;
        Node    tempTree[MAX_NTHREADS];
        long    tStart, tFinish;
        long    tElapsed;
   int i;
# ifdef SGC
   SGC_attr_t attr;
# endif

 if (1 == argc) {
     nthreads = 1;
 } else if (2 == argc) {
     nthreads = atoi(argv[1]);
     if (nthreads < 1 || nthreads > MAX_NTHREADS) {
  fprintf(stderr, "Invalid # of threads argument\n");
  exit(1);
     }
 } else {
     fprintf(stderr, "Usage: %s [# of threads]\n");
     exit(1);
 }
#       if defined(SGC)
   /* The University of Tokyo collector needs explicit */
   /* initialization.     */
   SGC_attr_init(&attr);
   SGC_init(nthreads, &attr);
#   endif
#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes or less .\n\n",
               2 * sizeof(Node0) * nthreads
          * (TreeSize(kLongLivedTreeDepth) + TreeSize(kMaxTreeDepth))
               + sizeof(double) * kArraySize);
        PrintDiagnostics();
       
# ifdef GC
   /* GC_expand_hp fails with empty heap */
   GC_malloc(1);
   GC_expand_hp(32*1024*1024*nthreads);
# endif

# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
        {
   pthread_t thread[MAX_NTHREADS];
   for (i = 1; i < nthreads; ++i) {
         int code;

     if ((code = pthread_create(thread+i, 0, run_one_test, 0)) != 0) {
           fprintf(stderr, "Thread creation failed %u\n", code);
       exit(1);
     }
   }
   /* We use the main thread to run one test.  This allows */
   /* profiling to work, for example.    */
   run_one_test(0);
   for (i = 1; i < nthreads; ++i) {
         int code;
     if ((code = pthread_join(thread[i], 0)) != 0) {
         fprintf(stderr, "Thread join failed %u\n", code);
           }
    }
        }
        PrintDiagnostics();

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
        return 0;
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o MT_GCBench2 MT_GCBench2.c -lgc

* 실행하기
$ ./MT_GCBench2
Garbage Collector Test
 Live storage will peak at 12388544 bytes or less .

 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 396 msec
        0x4b0038: Bottom up construction took 379 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 399 msec
        0x4b0038: Bottom up construction took 396 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 385 msec
        0x4b0038: Bottom up construction took 368 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 419 msec
        0x4b0038: Bottom up construction took 380 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 399 msec
        0x4b0038: Bottom up construction took 360 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 414 msec
        0x4b0038: Bottom up construction took 358 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 415 msec
        0x4b0038: Bottom up construction took 402 msec
Completed in 5504 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o MT_GCBench2 MT_GCBench2.c -lgc

* 실행하기
$ ./MT_GCBench2
Garbage Collector Test
 Live storage will peak at 12388544 bytes or less .

 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 54 msec
        0x4b0038: Bottom up construction took 41 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 40 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 40 msec
        0x4b0038: Bottom up construction took 42 msec
Completed in 581 msec
Completed 14 collections
Heap size is 33619968

 

 

 

 

Posted by Scripter
,

 

 

C 언어 소스:

// Filename: testHexView_02.c
//
//  Chapter 1.  Section 1.
//
//       A basic pattern of C++ Programing
//
// Compile: gcc -o testHexView_02 testHexView_02.c

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h> 

void toHex(char c, char a[3]);
void toHex8(int n, char a[10]);

int main(int argc, char *argv[])
{
    char *fname;
     FILE *file2;

    fpos_t fsize;
    long m;
    int i;

    char x;
    char s[3];
    char t[10];
    char buf[16];
    fpos_t n = 0L;

    struct stat stt;


    if (argc < 2)
    {
        printf("Usage: testHexView_02 [filename]\n");
        exit( 1 );
    }

    fname = argv[1];

    if (stat(fname, &stt) == 0 )
    {
        if ( stt.st_mode & S_IFDIR )
        {
            printf("\"%s\" is a directory\n", fname);
            exit( 1 );
        }
    }
   
    if (access(fname, R_OK) != 0)
    {
        printf("The file: \"%s\" is not readble.\n", fname);
        exit( 1 );
    }
 
    file2 = fopen(fname, "rb");

    if (!file2)
    {
        printf("Fail to open the file: \"%s\".\n", fname);
        exit( 1 );
    }

    s[2] = '\0';
    t[4] = ' ';
    t[9] = '\0';
    if (file2)
    {
        fseek(file2, 0, SEEK_END);    // seek to end of file
        fsize = ftell(file2);                 // get current file pointer

        printf("Its file size is %ld.\n\n", fsize);

        fseek(file2, 0, SEEK_SET);

        while(n < fsize && !feof(file2))
        {
            toHex8(n, t);
            printf("%s: ", t);
      
            fread(buf, sizeof(buf), 1, file2);
            m = (((fsize - n) < 16L) ? (long) (fsize - n) : 16L);
            for (i = 0; i < m; i++)
            {
                x = buf[i];
                toHex(x, s);
                printf("%s", s);
                if (i == 7)
                    printf("-");
                else
                    printf(" ");
            }
            if (m < 16)
            {
                for (i = 0; i < 16 - m; i++)
                {
                    printf("   ");
                }
            }

            printf("|");
            for (i = 0; i < m; i++)
            {
                if (buf[i] < ' ')
                    printf(".");
                else
                    printf("%c", buf[i]);
            }
            if (m < 16)
            {
                for (i = 0; i < 16 - m; i++)
                {
                    printf(" ");
                }
            }
            printf("|");

            n += m;
            printf("\n");
        }

        fclose(file2);
      
        printf("\n");;
        printf("Read %ld bytes.\n", n);
    }
    else {
        printf("Fail to read the file: \"%s\".,", fname);
    }
}

void toHex(char c, char a[3]) {
    int x1, x2;
    x1 = (c & 0xF0) >> 4;
    x2 = c & 0x0F;
    if (x1 < 10)
        a[0] = x1 + '0';
    else
        a[0] = (x1 - 10) + 'A';
    if (x2 < 10)
        a[1] = x2 + '0';
    else
        a[1] = (x2 - 10) + 'A';
}

void toHex8(int n, char a[10]) {
    int x1, x2, x3, x4, x5, x6, x7, x8;
    x1 = (n & 0xF0000000) >> 28;
    x2 = (n & 0xF000000) >> 24;
    x3 = (n & 0xF00000) >> 20;
    x4 = (n & 0xF0000) >> 16;
    x5 = (n & 0xF000) >> 12;
    x6 = (n & 0xF00) >> 8;
    x7 = (n & 0xF0) >> 4;
    x8 = n & 0x0F;
    if (x1 < 10)
        a[0] = x1 + '0';
    else
        a[0] = (x1 - 10) + 'A';
    if (x2 < 10)
        a[1] = x2 + '0';
    else
        a[1] = (x2 - 10) + 'A';
    if (x3 < 10)
        a[2] = x3 + '0';
    else
        a[2] = (x3 - 10) + 'A';
    if (x4 < 10)
        a[3] = x4 + '0';
    else
        a[3] = (x4 - 10) + 'A';
    a[4] = ' ';
    if (x5 < 10)
        a[5] = x5 + '0';
    else
        a[5] = (x5 - 10) + 'A';
    if (x6 < 10)
        a[6] = x6 + '0';
    else
        a[6] = (x6 - 10) + 'A';
    if (x7 < 10)
        a[7] = x7 + '0';
    else
        a[7] = (x7 - 10) + 'A';
    if (x8 < 10)
        a[8] = x8 + '0';
    else
        a[8] = (x8 - 10) + 'A';
}

 

 

MinGW의 gcc로 컴파일하기> gcc -o testHexView_02 testHexView_02.cpp

 

실행 예 1> testHexView_02 temp_1.bin
Its file size is 12.

0000 0000: 48 65 6C 6C 6F 20 74 68-65 72 65 0A             |Hello there.    |

Read 12 bytes.

 

실행 예 2> testHexView_02 myFile.ser
Its file size is 130.

0000 0000: AC ED 00 05 73 72 00 06-50 65 72 73 6F 6E 07 31 |....sr..Person.1|
0000 0010: 46 DB A5 1D 44 AB 02 00-03 49 00 03 61 67 65 4C |F...D....I..ageL|
0000 0020: 00 09 66 69 72 73 74 4E-61 6D 65 74 00 12 4C 6A |..firstNamet..Lj|
0000 0030: 61 76 61 2F 6C 61 6E 67-2F 53 74 72 69 6E 67 3B |ava/lang/String;|
0000 0040: 4C 00 08 6C 61 73 74 4E-61 6D 65 71 00 7E 00 01 |L..lastNameq.~..|
0000 0050: 78 70 00 00 00 13 74 00-05 4A 61 6D 65 73 74 00 |xp....t..Jamest.|
0000 0060: 04 52 79 61 6E 73 71 00-7E 00 00 00 00 00 1E 74 |.Ryansq.~......t|
0000 0070: 00 07 4F 62 69 2D 77 61-6E 74 00 06 4B 65 6E 6F |..Obi-want..Keno|
0000 0080: 62 69                                           |bi              |

Read 130 bytes.

 

 

Posted by Scripter
,

Visual C 용으로 OpenGL 용 소스를 작성할 떼는 헤더 파일 gl.h 와 glu.h 는 사용하지 않아도 된다. glut.h 하나만 사용하면 된다. 컴파일할 때는 헤더 파일을 위한 경로나 라이브러리 파일을 위한 경로를 별도로 지정하지 않아도 된다. 즉, 명령

 

    cl  소스파일명

으로 소스파일이 컴파일되어 실행파일이 생성된다. 아래 예제는 OpenGL Redebook 에 소개되어 있는 cube 예제 소스이다.

 

/*
 * Copyright (c) 1993-1997, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 * Permission to use, copy, modify, and distribute this software for
 * any purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright notice
 * and this permission notice appear in supporting documentation, and that
 * the name of Silicon Graphics, Inc. not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission.
 *
 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
 * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
 * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
 * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
 * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
 * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
 * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * US Government Users Restricted Rights
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
 * (c)(1)(ii) of the Rights in Technical Data and Computer Software
 * clause at DFARS 252.227-7013 and/or in similar or successor
 * clauses in the FAR or the DOD or NASA FAR Supplement.
 * Unpublished-- rights reserved under the copyright laws of the
 * United States.  Contractor/manufacturer is Silicon Graphics,
 * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
 *
 * OpenGL(R) is a registered trademark of Silicon Graphics, Inc.
 */

/*
 *  teapots.c
 *  This program demonstrates lots of material properties.
 *  A single light source illuminates the objects.
 */
#include <stdlib.h>
#include <GL/glut.h>

GLuint teapotList;

/*
 * Initialize depth buffer, projection matrix, light source, and lighting
 * model.  Do not specify a material property here.
 */
void init(void)
{
   GLfloat ambient[] = {0.0, 0.0, 0.0, 1.0};
   GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
   GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
   GLfloat position[] = {0.0, 3.0, 3.0, 0.0};

   GLfloat lmodel_ambient[] = {0.2, 0.2, 0.2, 1.0};
   GLfloat local_view[] = {0.0};

   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
   glLightfv(GL_LIGHT0, GL_POSITION, position);
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
   glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);

   glFrontFace(GL_CW);
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_AUTO_NORMAL);
   glEnable(GL_NORMALIZE);
   glEnable(GL_DEPTH_TEST);
/*  be efficient--make teapot display list  */
   teapotList = glGenLists(1);
   glNewList (teapotList, GL_COMPILE);
   glutSolidTeapot(1.0);
   glEndList ();
}

/*
 * Move object into position.  Use 3rd through 12th
 * parameters to specify the material property.  Draw a teapot.
 */
void renderTeapot(GLfloat x, GLfloat y,
   GLfloat ambr, GLfloat ambg, GLfloat ambb,
   GLfloat difr, GLfloat difg, GLfloat difb,
   GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine)
{
   GLfloat mat[4];

   glPushMatrix();
   glTranslatef(x, y, 0.0);
   mat[0] = ambr; mat[1] = ambg; mat[2] = ambb; mat[3] = 1.0;
   glMaterialfv(GL_FRONT, GL_AMBIENT, mat);
   mat[0] = difr; mat[1] = difg; mat[2] = difb;
   glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
   mat[0] = specr; mat[1] = specg; mat[2] = specb;
   glMaterialfv(GL_FRONT, GL_SPECULAR, mat);
   glMaterialf(GL_FRONT, GL_SHININESS, shine * 128.0);
   glCallList(teapotList);
   glPopMatrix();
}

/**
 *  First column:  emerald, jade, obsidian, pearl, ruby, turquoise
 *  2nd column:  brass, bronze, chrome, copper, gold, silver
 *  3rd column:  black, cyan, green, red, white, yellow plastic
 *  4th column:  black, cyan, green, red, white, yellow rubber
 */
void display(void)
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   renderTeapot(2.0, 17.0, 0.0215, 0.1745, 0.0215,
      0.07568, 0.61424, 0.07568, 0.633, 0.727811, 0.633, 0.6);
   renderTeapot(2.0, 14.0, 0.135, 0.2225, 0.1575,
      0.54, 0.89, 0.63, 0.316228, 0.316228, 0.316228, 0.1);
   renderTeapot(2.0, 11.0, 0.05375, 0.05, 0.06625,
      0.18275, 0.17, 0.22525, 0.332741, 0.328634, 0.346435, 0.3);
   renderTeapot(2.0, 8.0, 0.25, 0.20725, 0.20725,
      1, 0.829, 0.829, 0.296648, 0.296648, 0.296648, 0.088);
   renderTeapot(2.0, 5.0, 0.1745, 0.01175, 0.01175,
      0.61424, 0.04136, 0.04136, 0.727811, 0.626959, 0.626959, 0.6);
   renderTeapot(2.0, 2.0, 0.1, 0.18725, 0.1745,
      0.396, 0.74151, 0.69102, 0.297254, 0.30829, 0.306678, 0.1);
   renderTeapot(6.0, 17.0, 0.329412, 0.223529, 0.027451,
      0.780392, 0.568627, 0.113725, 0.992157, 0.941176, 0.807843,
      0.21794872);
   renderTeapot(6.0, 14.0, 0.2125, 0.1275, 0.054,
      0.714, 0.4284, 0.18144, 0.393548, 0.271906, 0.166721, 0.2);
   renderTeapot(6.0, 11.0, 0.25, 0.25, 0.25,
      0.4, 0.4, 0.4, 0.774597, 0.774597, 0.774597, 0.6);
   renderTeapot(6.0, 8.0, 0.19125, 0.0735, 0.0225,
      0.7038, 0.27048, 0.0828, 0.256777, 0.137622, 0.086014, 0.1);
   renderTeapot(6.0, 5.0, 0.24725, 0.1995, 0.0745,
      0.75164, 0.60648, 0.22648, 0.628281, 0.555802, 0.366065, 0.4);
   renderTeapot(6.0, 2.0, 0.19225, 0.19225, 0.19225,
      0.50754, 0.50754, 0.50754, 0.508273, 0.508273, 0.508273, 0.4);
   renderTeapot(10.0, 17.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01,
      0.50, 0.50, 0.50, .25);
   renderTeapot(10.0, 14.0, 0.0, 0.1, 0.06, 0.0, 0.50980392, 0.50980392,
      0.50196078, 0.50196078, 0.50196078, .25);
   renderTeapot(10.0, 11.0, 0.0, 0.0, 0.0,
      0.1, 0.35, 0.1, 0.45, 0.55, 0.45, .25);
   renderTeapot(10.0, 8.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0,
      0.7, 0.6, 0.6, .25);
   renderTeapot(10.0, 5.0, 0.0, 0.0, 0.0, 0.55, 0.55, 0.55,
      0.70, 0.70, 0.70, .25);
   renderTeapot(10.0, 2.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.0,
      0.60, 0.60, 0.50, .25);
   renderTeapot(14.0, 17.0, 0.02, 0.02, 0.02, 0.01, 0.01, 0.01,
      0.4, 0.4, 0.4, .078125);
   renderTeapot(14.0, 14.0, 0.0, 0.05, 0.05, 0.4, 0.5, 0.5,
      0.04, 0.7, 0.7, .078125);
   renderTeapot(14.0, 11.0, 0.0, 0.05, 0.0, 0.4, 0.5, 0.4,
      0.04, 0.7, 0.04, .078125);
   renderTeapot(14.0, 8.0, 0.05, 0.0, 0.0, 0.5, 0.4, 0.4,
      0.7, 0.04, 0.04, .078125);
   renderTeapot(14.0, 5.0, 0.05, 0.05, 0.05, 0.5, 0.5, 0.5,
      0.7, 0.7, 0.7, .078125);
   renderTeapot(14.0, 2.0, 0.05, 0.05, 0.0, 0.5, 0.5, 0.4,
      0.7, 0.7, 0.04, .078125);
   glFlush();
}

void reshape(int w, int h)
{
   glViewport(0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   if (w <= h)
      glOrtho(0.0, 16.0, 0.0, 16.0*(GLfloat)h/(GLfloat)w,
              -10.0, 10.0);
   else
      glOrtho(0.0, 16.0*(GLfloat)w/(GLfloat)h, 0.0, 16.0,
              -10.0, 10.0);
   glMatrixMode(GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}

/*
 * Main Loop
 */
int main(int argc, char **argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize(500, 600);
   glutInitWindowPosition(50,50);
   glutCreateWindow(argv[0]);
   init();
   glutReshapeFunc(reshape);
   glutDisplayFunc(display);
   glutKeyboardFunc (keyboard);
   glutMainLoop();
   return 0;
}

 

컴파일하기: cl teapots.c

실행하기: teapots

실행 결과:

 

 

 

 

Posted by Scripter
,

Visual C 용으로 OpenGL 용 소스를 작성할 떼는 헤더 파일 gl.h 와 glu.h 는 사용하지 않아도 된다. glut.h 하나만 사용하면 된다. 컴파일할 때는 헤더 파일을 위한 경로나 라이브러리 파일을 위한 경로를 별도로 지정하지 않아도 된다. 즉, 명령

 

    cl  소스파일명

으로 소스파일이 컴파일되어 실행파일이 생성된다. 아래 예제는 OpenGL Redebook 에 소개되어 있는 cube 예제 소스이다.

 

// Filename: cube.c
//
// See: http://www.glprogramming.com/red/chapter03.html

// #include <GL/gl.h>    // Commented out for Visual C
// #include <GL/glu.h>   // Commented out for Visual C
#include <GL/glut.h>

void init(void)
{
   glClearColor (0.0, 0.0, 0.0, 0.0);
   glShadeModel (GL_FLAT);
}

void display(void)
{
   glClear (GL_COLOR_BUFFER_BIT);
   glColor3f (1.0, 1.0, 1.0);
   glLoadIdentity ();             /* clear the matrix */
           /* viewing transformation  */
   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
   glScalef (1.0, 2.0, 1.0);      /* modeling transformation */
   glutWireCube (1.0);
   glFlush ();
}

void reshape (int w, int h)
{
   glViewport (0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
   glMatrixMode (GL_MODELVIEW);
}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   init ();
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutMainLoop();
   return 0;
}

 

컴파일하기: cl cube.c

실행하기: cube

실행 결과:

 

 

 

Posted by Scripter
,

양의 정수를 이진법으로 표현할 때 자리수를 구하는 C 언어 함수를 두 가지로 구현해 보았다.

함수 int nbits(int) 는 주어진 정수를 직접 2로 나누기를 반복하면서 자리수를 구한 것이고,

함수 int bits(int) 는 밑이 2인 로그함수 lg(x) = log(x)/log(2) 를 이용하여 구한 것이다.

그런데 Cygwin 또는 Linux 에서 gcc 로 컴파일하여 실행하면 오루가 빌생한다. (참고로 gcc 의 버전은 4.5.3 이다.) MinGW 의 gcc 는 버전이 4.6.2 인데 마찬가지로 log 계산에 오류가 있다.

Visual C, C#, Java, Python 으로는 2100000000 이하의 양의 정수에 대하여 그런 오류가 발생하지 않는다.

// Filename: calcLG64.c
//
//        1) Calculate the number of bits of binary format of a given positive integer,
//        2) Compare it with lg(n) + 1 = log(n)/log(2) + 1
//
//   Compiling with Visual C++ 10.
//   Compile: cl calcLG64.c
//   Execute: calcLG64
//
//     Or
//
//   Compiling with GCC on Cygwin.
//   Compile: gcc -o calcLG64.exe calcLG64.c
//   Execute: ./calcLG64
//
//   Date: 2013. 2. 25.
//  Author: pkim __AT__ scripts ((DOT)) pe ((DOT)) kr

#include <stdio.h>
#include <math.h>

int nbits(int n)
{
    int i = 0;
    while (n > 0) {
        n >>= 1;
        i++;
    }
    return i;
}

double bits(int n)
{
    return (int) (log((double)n)/log(2.0)) + 1;
}


int main()
{
    int i;
    int k1, k2;
   
    for (i = 1; i <= 65537; i++)
    {
     k1 = nbits(i);
     k2 = bits(i);
     if (k1 != k2) {
            printf("%7d:   k1 = nbits(%5d) = %2d", i, i, k1);
            printf(",   k2 = lg(%5d) + 1 = %2d\n", i, k2);
        }
    }
   
    return 0;
}

/*
Output with G++ on Cygwin
      8:  k1 = nbits(    8) =  4,   k2 = lg(    8) + 1 =  3
     64:  k1 = nbits(   64) =  7,   k2 = lg(   64) + 1 =  6
    128:  k1 = nbits(  128) =  8,   k2 = lg(  128) + 1 =  7
   4096:  k1 = nbits( 4096) = 13,   k2 = lg( 4096) + 1 = 12
   8192:  k1 = nbits( 8192) = 14,   k2 = lg( 8192) + 1 = 13
  16384:  k1 = nbits(16384) = 15,   k2 = lg(16384) + 1 = 14
  32768:  k1 = nbits(32768) = 16,   k2 = lg(32768) + 1 = 15
*/

/*
Output with Visual C++ 10 on Windows XP:
*/

 

또 다음은 C++ 언어로 작성한 것인데, g++ 로 컴파일하여 실행한 것도 역시 log 계산에 오류가 있음을 보여준다.

// Filename: calcLG64.cpp
//
//        1) Calculate the number of bits of binary format of a given positive integer,
//        2) Compare it with lg(n) + 1 = log(n)/log(2) + 1
//
//   Compiling with Visual C++ 10.
//   Compile: cl /EHsc calcLG64.cpp
//   Execute: calcLG64
//
//     Or
//
//   Compiling with G++ on Cygwin.
//   Compile: g++ -o calcLG64 calcLG64.cpp
//   Execute: ./calcLG64
//
//   Date: 2013. 2. 23.
//  Author: pkim __AT__ scripts ((DOT)) pe ((DOT)) kr

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

#include <iomanip>
using std::setw;
 

int nbits(int n)
{
 int i = 0;
 while (n > 0) {
  n >>= 1;
  i++;
 }
 return i;
}

double bits(int n)
{
 return (int) (log((double)n)/log(2.0)) + 1;
}


int main()
{
    int i;
    int k1, k2;
   
    for (i = 1; i <= 65537; i++)
    {
     k1 = nbits(i);
     k2 = bits(i);
     if (k1 != k2) {
            cout << setw( 7 ) << i << ":  k1 = nbits(" << setw( 5 ) << i << ") = " << setw( 2 ) << k1;
            cout << ",   k2 = lg(" << setw( 5 ) << i << ") + 1 = " << setw( 2 ) << k2 << endl;
        }
    }
}

/*
Output with G++ on Cygwin
      8:  k1 = nbits(    8) =  4,   k2 = lg(    8) + 1 =  3
     64:  k1 = nbits(   64) =  7,   k2 = lg(   64) + 1 =  6
    128:  k1 = nbits(  128) =  8,   k2 = lg(  128) + 1 =  7
   4096:  k1 = nbits( 4096) = 13,   k2 = lg( 4096) + 1 = 12
   8192:  k1 = nbits( 8192) = 14,   k2 = lg( 8192) + 1 = 13
  16384:  k1 = nbits(16384) = 15,   k2 = lg(16384) + 1 = 14
  32768:  k1 = nbits(32768) = 16,   k2 = lg(32768) + 1 = 15
*/

/*
Output with Visual C++ 10 on Windows XP:
*/

 

gcc 에는 2를 밑으로 하는 로그함수 log2 기 이미 구현되어 있다. 그래서 log2(8) 을 테스트해보았는데, floor(log2(8)) 에 대하여 역시 오류가 발생한다. 신기한 것은 옵션 -std=c99 -lm 을 붙여서 컴파일하여 실행하면 오류가 발생한다는 점이다. (참고로, Visual C++ 는 Visual Studio 2012 에서 처음으로 log2 함수가 지원된다.)

// Filename: test_log2.c
//
//  Compile: gcc -o test_log2 test_log2.c
//  Compile: gcc -o test_log2 test_log2.c -std=c99 -lm
//  Execute: ./test_log2 [number]
//
//   See: http://www.linuxquestions.org/questions/programming-9/log2-not-found-367355/

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
// #include <amp_math.h>   // for log2()
                           // supported in Visual Studio 2012
                           // See: http://msdn.microsoft.com/en-us/library/hh308239.aspx
                          
int main( int argc, char *argv[] )
{
  double log_base_2 = 0;
  double given_value;

  if( argc < 2 )
  {
    fprintf( stderr, "ERROR! You must give a numeric argument!\n" );
    return 1;
  }

  given_value = strtod( argv[1], NULL );

  log_base_2 = log2( given_value );
  printf( "Log base 2 of %f is %f\n",
  //printf( "Log base 2 of %f is %.15f\n",
          given_value,
          log_base_2 );

  printf( "Floor of log base 2 of %f is %f\n",
          given_value,
          floor(log_base_2) );

  return 0;
}

/*
Compile and Execute:
$ gcc -o test_log2 test_log2.c
$ ./test_log2 8
Log base 2 of 8.000000 is 3.000000
Floor of log base 2 of 8.000000 is 3.000000

Compile and Execute:
$ gcc -o test_log2 test_log2.c -std=c99 -lm
$ ./test_log2 8
Log base 2 of 8.000000 is 3.000000
Floor of log base 2 of 8.000000 is 2.000000
*/

 

 

Posted by Scripter
,

 

C 언어로 배정밀도 부동소수점수(floating point number of double type)로 높은 차수의 다항식 값을 계산을 하는 경우의 오차에 대하여 생각해보기로 하자. 우선 0.7 을 (배정밀도이든 단정밀도이든 상관없이) 부동소수점수로 정확하게 기억시키는 방법은 없다. 0.7 을 배정밀도 부동소수점수(double 타입의 수)로 처리하여 십진법수로 표현하면 유효숫자가 겨우 14개 내지 15개 정도 밖에 되지 않는다.  수 1 에 비하여 오차 1.0e-15 는 상대적으로 매우 작은 오차이다. 그러나 차수가 매우 높은 다항식 함수는 아주 짧은 구간(간격이 약 1.0e-15  인 구간) 안에서도 매우 많은 진동을 하여 함수값의 차이는 매우 커질 수가 있으니 주의해야 한다.

식 f(x) = 2*x*x - 1 로 정의되는 함수 f 를 생각해 보자. x 가 폐구간 [-1,1] 안에 있으면 f(x) 도 이 구간 안에 있다. 즉 f 는 f : [-1, 1] -> [-1, 1] 인 함수이다. 더군다나 이 함수는 두 개의 부동점(fixed point, 즉 f(x) = x 인 x)을 갖는 함수이다. 방정식 2*x*x - 1 = x 플 풀면 근이 -0.5 와 1 이다, 실제로 f(1) = 1 이고 f(-0.5) = -0.5 이다. 이제 53 개의 f 를 반복해서 합성한 함수를 g 로 놓고  g(0.7) 을 계산해 보자. g(0.7) 의 값의 오차가 어떠할런지... 

아래는 C 언어로 g(0.7) = f^(53) (0.7) 을 계산해 본 소스이다. 결과는 참값에 비하여 오차가 너무 큰 근사값(즉 유효하지 않은 근사값))이 된다는 것이다. 참고로 g(x) 는 2^53 차(즉, 9007199254740992 차)의 다항식 함수이다.

 

//  Filename: AccumulativeError07.c
//
//          This illustrates that a tiny error gives a big error
//          in the evaluation of a polynomial of very high degree,
//
//   Compile: gcc AccumulativeError07 AccumulativeError07.c
//   Execute: ./AccumulativeError07
//
//     Or
//
//   Compile: cl AccumulativeError07.c
//   Execute: AccumulativeError07
//
//  Date: 2013. 1. 22.
//  Copyright (c) 2013 PH Kim  (pkim __AT__ scripts.pe.kr)


#include <stdio.h>

#define REPEAT 53

double f(double x)
{
    return 2.0*x*x - 1.0;
}

int main()
{
    double x = 0.7;
    double y, t;
    int i;

    printf("x = %g\n", x);
    printf("x = %f\n", x);
    printf("x = %.15f\n", x);
    printf("x = %.16f\n", x);
    printf("x = %.20f\n", x);
    printf("\n");

    printf("f is a function defined by f(x) = 2*x*x - 1\n");
    printf("f^(n) (x) means the n times composite of the function f(x),\n");
    printf("say, f^(2) (x) = f(f(x)), f^(2) (x) = f(f(f(x))), and etc\n");
    printf("\n");

    t = x;
    for (i = 1; i <= REPEAT; i++) {
        y = f(t);
        t = y;
    }

    printf("y = f^(53) (x) = f^(53) (%g) = %g\n", x, y);
    printf("y = f^(53) (x) = f^(53) (%g) = %f\n", x, y);
    printf("y = f^(53) (x) = f^(53) (%g) = %.15f\n", x, y);
    printf("y = f^(53) (x) = f^(53) (%g) = %.16f\n", x, y);
    printf("y = f^(53) (x) = f^(53) (%g) = %.20f\n", x, y);
    printf("Is it true?\n");
    printf("\n");

    printf("Its error is too big.\nThe iterated value shoul be -0.5671977142553364749...\n");
    printf("\n");

    return 0;
}

/*
Output:
x = 0.7
x = 0.700000
x = 0.700000000000000
x = 0.7000000000000000
x = 0.69999999999999996000

f is a function defined by f(x) = 2*x*x - 1
f^(n) (x) means the n times composite of the function f(x),
say, f^(2) (x) = f(f(x)), f^(2) (x) = f(f(f(x))), and etc

y = f^(53) (x) = f^(53) (0.7) = 0.538614
y = f^(53) (x) = f^(53) (0.7) = 0.538614
y = f^(53) (x) = f^(53) (0.7) = 0.538614158130321
y = f^(53) (x) = f^(53) (0.7) = 0.5386141581303205
y = f^(53) (x) = f^(53) (0.7) = 0.53861415813032054000
Is it true?

Its error is too big.
The iterated value shoul be -0.5671977142553364749...
*/

 

 

 

Posted by Scripter
,

C 언어로 작성된 다음 소스를 컴파일하여 실행하면 숫자 계산으로 쌓아 올린 피라미드 세 가지가 출력된다. (gcc 는 GNU C 컴파일러의 컴파일 명령이고, cl 은 Visual C++ 컴파일러의 컴파일 명령이다.)

세 함수 pyra1(int, int), pyra2(int, int), pyra3(int, int) 은 재귀호출을 사용하였고, 세 함수 pyramid1(), pyramid2(), pyramid3() 은 for 반복문을 사용하였다.

 

//  Filename: pyramidOfDigits2.c
//
//   Compile: gcc -o pyramidOfDigits2 pyramidOfDigits2.c
//   Execute: ./pyramidOfDigits2
//
//     Or
//
//   Compile: cl pyramidOfDigits2.c
//   Execute: pyramidOfDigits2
//
//     See: http://darvish.wordpress.com/2008/03/16/the-beauty-of-mathematics-and-the-love-of-god/
//
//  Date: 2013. 1. 22.
//  Copyright (c) 2013 PH Kim  (pkim __AT__ scripts.pe.kr)


#include <stdio.h>

#define TEN    10
#define NINE   9
#define EIGHT   8

// initial calling: pyra1(1, 1)
void pyra1(int n, int i)
{
    if (i <= NINE) {
        printf("%9d x %d + %d = %d\n", n, EIGHT, i, n*EIGHT + i);
        if (i < NINE) {
            pyra1(n*TEN + (i + 1), i + 1);
        }
    }
}

// initial calling: pyra2(9, 7)
void pyra2(int n, int i)
{
    if (i >= 0) {
        printf("%8d x %d + %d = %d\n", n, NINE, i, n*NINE + i);
        if (i > 0) {
            pyra2(n*TEN + (i + 1), i - 1);
        }
    }
}

// initial calling: pyra3(1, 2)
void pyra3(int n, int i)
{
    if (i <= TEN) {
        printf("%9d x %d + %2d = %d\n", n, NINE, i, n*NINE + i);
        if (i < TEN) {
            pyra3(n*TEN + i, i + 1);
        }
    }
}

void pyramid1()
{
    int i, n;
    char s[TEN];

    for (i = 1; i < TEN; i++) {
        s[i - 1] = (char) (48 + i);
        s[i] = '\0';
        sscanf(s, "%d", &n);
        printf("%9d x %d + %d = %d\n", n, EIGHT, i, n*EIGHT + i);
    }
}

void pyramid2()
{
    int i, n;
    char s[TEN];

    for (i = NINE; i > 1; i--) {
        s[NINE - i] = (char) (48 + i);
        s[NINE - i + 1] = '\0';
        sscanf(s, "%d", &n);
        printf("%8d x %d + %d = %d\n", n, NINE, i - 2, n*NINE + (i - 2));
    }
}

void pyramid3()
{
    int i, n;
    char s[TEN];

    for (i = 1; i < TEN; i++) {
        s[i - 1] = (char) (48 + i);
        s[i] = '\0';
        sscanf(s, "%d", &n);
        printf("%9d x %d + %2d = %d\n", n, NINE, i + 1, n*NINE + (i + 1));
    }
}

int main()
{
    printf("Use for loops\n");
    printf("Pyramid 1\n");
    pyramid1();
    printf("\n");

    printf("Pyramid 2\n");
    pyramid2();
    printf("\n");

    printf("Pyramid 3\n");
    pyramid3();
    printf("\n");


    printf("Use recursively called functions\n");
    printf("Pyramid 1\n");
    pyra1(1, 1);
    printf("\n");

    printf("Pyramid 2\n");
    pyra2(9, 7);
    printf("\n");

    printf("Pyramid 3\n");
    pyra3(1, 2);
    printf("\n");

    return 0;
}

 

 

 

Posted by Scripter
,

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

음이 아닌 실수 A 의 평방근 sqrt(A) 를 구하는 Heron 의 방법:

        반복함수  g(x) = (x + A/x) / 2   를 이용

 

실수 A 의 n제곱근 root(n, A) 를 구하는 Newton-Raphson 의 방법

        반복함수  g(x) = ((n-1)*x + A/(x**(n - 1))) / n    를 이용

n = 2 인 경우에는 Newton-Raphson 의 방법이 Heron 의 방법과 동일하다.

(참조. http://en.wikipedia.org/wiki/Newton's_method )

 

(math.h 를 인클루드하여 사용하는) C 언어의 표준 수학 라이브러리에 지수 계산 함수 pow() 가 이미 구현되어 있다. 하지만 차후 필요한 데가 있을 것 같아서 이와 유사한 n 제곱 함수와 n 제곱근 함수를 구현해 보았다.

지수가 정수인 거듭제곱을 계산하는  함수도 nPow(), gPow, mPow() 세 개 구현해 놓았는데, 이들 세 함수는 절차적 언어의 성능상 재귀호출이 아니고 단순 반복 기법을 사용하는 함수이다. 이 세 함수 중 mPow() 의 성능이 가장 우수하다. 큰 지수의 경우 for 반복문의 반복회수를 따져 보면 성능 비교를 할 수 있을 것이다. (성능 비교를 위해 세 가지를 모두 소스에 남겨 두었다.) mPow() 함수는 n 제곱근을 구하는 재귀함수 newtonNthRoot(int, double) 의 구현에 사용되기도 한다. if ... else ... 구문이 많아 소스가 복잡하게 보일지 모르겠으나 이는 밑수나 지수가 음수이거나 0인 경우의 처리를 위함이다. 구현된 모든 함수의 구현에는 예외상황(예를 들어, 음수의 짝수 제곱근 같은 예외상황) 처리 과정이 있다.

아래의 소스는 Visual C++ 외에 gcc 로 컴파일해도 수정 없이 잘 되리라고 본다.

예외상황 처리룰 하기 위해, C 언어에서는 sejmp.h 를 인클루드하고, 예외상황을 던질 때는 longjmp() 함수를, 예외상황을 받을 때는 setjmp() 함수와 switch{ ... } 문을 사용한다.

// Filename: testNthRoot.c
//
//            Approximate square roots, cubic roots and n-th roots of a given number.
//
// Compile: cl testNthRoot.c
// Execute: testNthRoot
//
// Date: 2013. 1. 6.
// Copyright (c) 2013 PH Kim  (pkim __AT__ scripts.pe.kr)


#include <stdio.h>
#include <math.h>
#include <setjmp.h>

jmp_buf g_stkBuf;

#define NO_EXCEPTION          (0)
#define CANNOT_EVALUATE    (100)

#define MAX_ITER 20000
#define M_EPSILON 1.0e-15


 

/**
  * Compute the n-th root of x to a given scale, x > 0.
  */
double nPow(double a, int n)
{
    int i;
    double y;

    if (n > 0) {
        if (n == 1)
            return a;
        else {
            if (a == 0.0 || a == 1.0) {
                return a;
            }
            else if (a == -1.0) {
                if (n % 2 == 1)
                    return -1.0;
                else
                    return 1.0;
            }
            else if (a < 0.0) {
                if (n % 2 == 1)
                    return -nPow(-a, n);
                else
                    return nPow(-a, n);
            }
            else {
                y = 1.0;
                for (i = 0; i < n; i++) {
                    y *= a;
                }
                return y;
            }
        }
    }
    else if (n == 0) {
        return 1.0;
    }
    else {      //  when n < 0
        if (a == 0.0) {
            printf("Negative powering exception of zero.\n");
            longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
            return -1.0;
        }
        else {
            if (n == -1)
                return 1.0/a;
            else
                return 1.0/nPow(a, -n);
        }
    }
}

 

/**
  * Compute the n-th root of x to a given scale, x > 0.
  */
double gPow(double a, int n)
{
    int i;
    double y;
    double r;
    int m;
    int one;

    if (n > 0) {
        if (n == 1)
            return a;
        else {
            if (a == 0.0 || a == 1.0) {
                return a;
            }
            else if (a == -1.0) {
                if (n % 2 == 1)
                    return -1.0;
                else
                    return 1.0;
            }
            else if (a < 0.0) {
                if (n % 2 == 1)
                    return -gPow(-a, n);
                else
                    return gPow(-a, n);
            }
            else {

                y = 1.0;
                r = a;
                m = 8*sizeof(int) - 1;    // 8*sizeof(int) - 1;  ignore sign bit, which is MSB
                one = 1;
                for (i = 0; i < m; i++) {
                    if ((n & one) == 0) {
                        y *= 1.0;
                    }
                    else {
                        y *= r;
                    }
                    r = r*r;
                    one <<= 1;
                    if (one > n)
                        break;
                }
                return y;
            }
        }
    }
    else if (n == 0) {
        return 1.0;
    }
    else {      //  when n < 0
        if (a == 0.0) {
            printf("Negative powering exception of zero.\n");
            longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
            return -1.0;
        }
        else {
            if (n == -1)
                return 1.0/a;
            else
                return 1.0/gPow(a, -n);
        }
    }
}

 

/**
  * Compute the n-th root of x to a given scale, x > 0.
  */
double mPow(double a, int n)
{
    if (n > 0) {
        if (n == 1)
            return a;
        else {
            if (a == 0.0 || a == 1.0) {
                return a;
            }
            else if (a == -1.0) {
                if (n % 2 == 1)
                    return -1.0;
                else
                    return 1.0;
            }
            else if (a < 0.0) {
                if (n % 2 == 1)
                    return -mPow(-a, n);
                else
                    return mPow(-a, n);
            }
            else {

                double y = 1.0;
                double r = a;
                int m = n;
                while (m > 0) {
                    if ((m & 0x1) != 0) {
                        y *= r;
                    }
                    r = r*r;
                    m >>= 1;
                }
                return y;
            }
         }
    }
    else if (n == 0) {
        return 1.0;
    }
    else {      //  when n < 0
        if (a == 0.0) {
            printf("Negative powering exception of zero.\n");
            longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
            return -1.0;
        }
        else {
            if (n == -1)
                return 1.0/a;
            else
                return 1.0/mPow(a, -n);
        }
    }
}

 

/**
  * Compute the square root of x to a given scale, x > 0.
  */
double heronSqrt(double a)
{
    double x1, x2, er;
    int counter;

    if (a < 0.0) {
        printf("Cannot find the sqrt of a negative number.\n");
        longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
                                                 // errNo는 setjmp로 설정한 지점으로 복귀할 때 리턴 값
        return -1.0;
    }
    else if (a == 0.0 || a == 1.0) {
        return a;
    }
    else {
        x1 = a;
        x2 = (x1 + a/x1)/2.0;
        er = x1 - x2;
        counter = 0;
        while (x1 + er != x1) {
            x1 = x2;
            x2 = (x1 + a/x1)/2.0;
            er = x1 - x2;
            if (fabs(er) < fabs(M_EPSILON*x1))
                break;
            counter++;
            if (counter > MAX_ITER)
                break;
        }
        if (counter >= MAX_ITER) {
            printf("Inaccurate sqrt exception by too many iterations.\n");
            longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
            return -1.0;
        }
        return x2;
    }
}

/**
  * Compute the cubic root of x to a given scale, x > 0.
  */
double newtonCbrt(double a)
{
    double x1, x2, er;
    int counter;

    if (a == 0.0 || a == 1.0 || a == -1.0) {
        return a;
    }
    else if (a < 0.0) {
        return -newtonCbrt(-a);
    }
    else {
        x1 = a;
        x2 = (2.0*x1 + a/(x1*x1))/3.0;
        er = x1 - x2;
        counter = 0;
        while (x1 + er != x1) {
            x1 = x2;
            x2 = (2.0*x1 + a/(x1*x1))/3.0;
            er = x1 - x2;
            if (fabs(er) < fabs(M_EPSILON*x1))
                break;
            counter++;
            if (counter > MAX_ITER)
                break;
        }
        if (counter >= MAX_ITER) {
            printf("Inaccurate cbrt exception by too many iterations.\n");
            longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
            return -1.0;
        }
        return x2;
    }
}

/**
  * Compute the n-th root of x to a given scale, x > 0.
  */
double newtonNthRoot(int n, double a)
{
    double x1, x2, xn, er;
    int counter;

    if (n == 0) {
        return 1.0;
    }
    else if (n == 1) {
        return a;
    }
    else if (n > 0) {
        if (a == 0.0 || a == 1.0) {
            return a;
        }
        else if (a == -1.0) {
            if (n % 2 == 1)
                return a;
            else {
                printf("Cannot find the even n-th root of a negative number.\n");
                longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
                return -1.0;
            }
        }
        else if (a < 0.0) {
            if (n % 2 == 1)
                return -newtonNthRoot(n, -a);
            else {
                printf("Cannot find the even n-th root of a negative number.\n");
                longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
                return -1.0;
            }
        }
        else if (a < 1.0) {
            return 1.0/newtonNthRoot(n, 1.0/a);
        }
        else {
            x1 = a;
            xn = mPow(x1, n - 1);
            x2 = ((n - 1)*x1 + a/xn)/n;
            er = x1 - x2;
            counter = 0;
            while (x1 + er != x1) {
                x1 = x2;
                xn = mPow(x1, n - 1);
                x2 = ((n - 1)*x1 + a/xn)/n;
                er = x1 - x2;
                if (fabs(er) < fabs(M_EPSILON*x1))
                    break;
                counter++;
                if (counter > MAX_ITER)
                    break;
            }
            if (counter >= MAX_ITER) {
                printf("Inaccurate n-th exception by too many iterations.\n");
                longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
                return -1.0;
            }
            return x2;
        }
    }
    else {
        if (a == 0.0) {
            printf("Cannot find the negative n-th root of zero.\n");
            longjmp( g_stkBuf, CANNOT_EVALUATE );  // setjmp로 설정한 g_stkBuf(스택정보)를 가지고 해당 시점으로 복귀
            return -1.0;
        }
        else {
            return 1.0/newtonNthRoot(-n, a);
        }
    }
}

 

int main()
{
    double x = 16.0;
    double u = sqrt(x);

    int k;
    double t1, t2, t3;
    double y, z, w;

    int errNo = NO_EXCEPTION;

    printf("[ Testing heronSqrt(double) ]--------------------\n");
    printf("x = %g\n", x);
    printf("u = sqrt(%g) = %g\n", x, u);
    y = heronSqrt(x);
    printf("y = heronSqrt(%g) = %g\n", x, y);
    printf("y*y = %g\n", y*y);
    printf("\n");

    printf("[ Testing newtonCbrt(double) ]--------------------\n");
    x = -216.0;
    printf("x = %g\n", x);
    printf("-exp(log(-x)/3.0) = %g\n", -exp(log(-x)/3.0));
    w = newtonCbrt(x);
    printf("w = newtonCbrt(%g) = %g\n", x, w);
    printf("w*w*w = %g\n", w*w*w);
    printf("\n");

    x = 729000000000.0;
    printf("x = %g\n", x);
    printf("exp(log(x)/3.0) = %g\n", exp(log(x)/3.0));
    w = newtonCbrt(x);
    printf("w = newtonCbrt(%g) = %g\n", x, w);
    printf("w*w*w = %g\n", w*w*w);
    printf("\n");

    printf("[ Testing newtonNthRoot(int, double) ]--------------------\n");
    z = newtonNthRoot(3, x);
    printf("x = %g\n", x);
    printf("z = newtonNthRoot(3, %g) = %g\n", x, z);
    printf("z*z*z = %g\n", z*z*z);
    printf("\n");

    x = 12960000000000000000.0;
    z = newtonNthRoot(4, x);
    printf("x = %g\n", x);
    printf("z = newtonNthRoot(4, x) = newtonNthRoot(4, %g) = %g\n", x, z);
    printf("z*z*z*z = %g\n", z*z*z*z);
    printf("\n");

    x = 1.0/12960000000000000000.0;
    z = newtonNthRoot(4, x);
    printf("x = %g\n", x);
    printf("exp(log(x)/4.0) = %g\n", exp(log(x)/4.0));
    printf("z = newtonNthRoot(4, x) = newtonNthRoot(4, %g) = %g\n", x, z);
    printf("z*z*z*z = %g\n", z*z*z*z);
    printf("\n");


    errNo = setjmp( g_stkBuf );  // longjmp로 복귀할 지점을 설정, g_stkBuf에 스택정보 저장
    switch ( errNo )
    {
        case NO_EXCEPTION:
            x = -4.0;
            printf("[ Test Exception heronSqrt(double) ]--------------------\n");
            printf("x = %g\n", x);
            printf("Calculating heronSqrt(%g)\n" , x);
            y = heronSqrt(x);
            printf("y = heronSqrt(%g) = %g\n", x, y);
            printf("y*y = %g\n", y*y);
            printf("\n");
            break;
        case CANNOT_EVALUATE:
            printf("Caught some exception in calculating heronSqrt(%g)\n", x);
            printf("\n");
            errNo = NO_EXCEPTION;
            break;
    }


    errNo = setjmp( g_stkBuf );  // longjmp로 복귀할 지점을 설정, g_stkBuf에 스택정보 저장
    switch ( errNo )
    {
        case NO_EXCEPTION:
            x = -4.0;
            printf("[ Test Exception in newtonCbrt(double) ]--------------------\n");
            printf("x = %g\n", x);
            printf("Calculating newtonCbrt(%g)\n", x);
            y = newtonCbrt(x);
            printf("y = newtonCbrt(%g) = %g\n", x, y);
            printf("y*y*y = %g\n", y*y*y);
            printf("\n");
            break;
        case CANNOT_EVALUATE:
            printf("Caught some exception in calculating newtonCbrt(%g)\n", x);
            printf("\n");
            errNo = NO_EXCEPTION;
            break;
    }

    printf("[ Test calculations by powering ]-----------------------------\n");
    x = 200.0;
    z = newtonNthRoot(10, x);
    printf("x = %g\n", x);
    printf("exp(log(x)/10.0) = %g\n", exp(log(x)/10.0));
    printf("z = newtonNthRoot(10, x) = newtonNthRoot(10, %g) = %g\n", x,  z);
    printf("pow(z, 10) = %g\n", pow(z, 10));
    printf("\n");

    x = 3001.0;
    z = newtonNthRoot(99, x);
    printf("x = %g\n", x);
    printf("exp(log(x)/99.0) = %g\n", exp(log(x)/99.0));
    printf("z = newtonNthRoot(99, x) = newtonNthRoot(99, %g) = %g\n", x, z);
    printf("pow(z, 99) = %g\n", pow(z, 99));
    printf("\n");

    x = 3001.0;
    z = newtonNthRoot(-99, x);
    printf("x = %g\n", x);
    printf("exp(log(x)/-99.0) = %g\n", exp(log(x)/-99.0));
    printf("z = newtonNthRoot(-99, x) = newtonNthRoot(-99, %g) = %g\n", x, z);
    printf("1.0/pow(z, 99) = %g\n", 1.0/pow(z, 99));
    printf("\n");

    printf("2.1**2.1 = pow(2.1, 2.1) = %g\n", pow(2.1, 2.1));
    printf("2.1**(-2.1) = pow(2.1, -2.1) = %g\n", pow(2.1, -2.1));
    printf("2.1**2.1 * 2.1**(-2.1) = pow(2.1, 2.1) * pow(2.1, -2.1) = %g\n", pow(2.1, 2.1)*pow(2.1, -2.1));
    printf("2.1**2.1 = exp(2.1*log(2.1)) = %g\n", exp(2.1*log(2.1)));
    printf("2.1**(-2.1) = exp(-2.1*log(2.1)) = %g\n", exp(-2.1*log(2.1)));
    printf("2.1**2.1 * 2.1**(-2.1) = exp(2.1*log(2.1)) * exp(-2.1*log(2.1)) = %g\n", exp(2.1*log(2.1)) * exp(-2.1*log(2.1)));
    printf("\n");


    k = 301;
    x = -1.029;
    t1 = nPow(x, k);
    t2 = gPow(x, k);
    t3 = mPow(x, k);
    printf("t1 = nPow(%g, %d) = %g\n", x, k, t1);
    printf("t2 = gPow(%g, %d) = %g\n", x, k, t2);
    printf("t3 = mPow(%g, %d) = %g\n", x, k, t3);
    printf("t1 / t2 = %g\n", t1 / t2);
    printf("t1 - t2 = %g\n", t1 - t2);
    printf("t1 == t2 ? %s\n",  t1 == t2 ? "yes" : "no");
    printf("t1 / t3 = %g\n", t1 / t3);
    printf("t1 - t3 = %g\n", t1 - t3);
    printf("t1 == t3 ? %s\n",  t1 == t3 ? "yes" : "no");
    printf("t2 / t3 = %g\n", t2 / t3);
    printf("t2 - t3 = %g\n", t2 - t3);
    printf("t2 == t3 ? %s\n",  t2 == t3 ? "yes" : "no");
    printf("\n");

    printf("Done.\n");

}

/*
Output:
[ Testing heronSqrt(double) ]--------------------
x = 16
u = sqrt(16) = 4
y = heronSqrt(16) = 4
y*y = 16

[ Testing newtonCbrt(double) ]--------------------
x = -216
-exp(log(-x)/3.0) = -6
w = newtonCbrt(-216) = -6
w*w*w = -216

x = 7.29e+011
exp(log(x)/3.0) = 9000
w = newtonCbrt(7.29e+011) = 9000
w*w*w = 7.29e+011

[ Testing newtonNthRoot(int, double) ]--------------------
x = 7.29e+011
z = newtonNthRoot(3, 7.29e+011) = 9000
z*z*z = 7.29e+011

x = 1.296e+019
z = newtonNthRoot(4, x) = newtonNthRoot(4, 1.296e+019) = 60000
z*z*z*z = 1.296e+019

x = 7.71605e-020
exp(log(x)/4.0) = 1.66667e-005
z = newtonNthRoot(4, x) = newtonNthRoot(4, 7.71605e-020) = 1.66667e-005
z*z*z*z = 7.71605e-020

[ Test Exception heronSqrt(double) ]--------------------
x = -4
Calculating heronSqrt(-4)
Cannot find the sqrt of a negative number.
Caught some exception in calculating heronSqrt(-4)

[ Test Exception in newtonCbrt(double) ]--------------------
x = -4
Calculating newtonCbrt(-4)
y = newtonCbrt(-4) = -1.5874
y*y*y = -4

[ Test calculations by powering ]-----------------------------
x = 200
exp(log(x)/10.0) = 1.69865
z = newtonNthRoot(10, x) = newtonNthRoot(10, 200) = 1.69865
pow(z, 10) = 200

x = 3001
exp(log(x)/99.0) = 1.08424
z = newtonNthRoot(99, x) = newtonNthRoot(99, 3001) = 1.08424
pow(z, 99) = 3001

x = 3001
exp(log(x)/-99.0) = 0.922308
z = newtonNthRoot(-99, x) = newtonNthRoot(-99, 3001) = 0.922308
1.0/pow(z, 99) = 3001

2.1**2.1 = pow(2.1, 2.1) = 4.74964
2.1**(-2.1) = pow(2.1, -2.1) = 0.210542
2.1**2.1 * 2.1**(-2.1) = pow(2.1, 2.1) * pow(2.1, -2.1) = 1
2.1**2.1 = exp(2.1*log(2.1)) = 4.74964
2.1**(-2.1) = exp(-2.1*log(2.1)) = 0.210542
2.1**2.1 * 2.1**(-2.1) = exp(2.1*log(2.1)) * exp(-2.1*log(2.1)) = 1

t1 = nPow(-1.029, 301) = -5457.93
t2 = gPow(-1.029, 301) = -5457.93
t3 = mPow(-1.029, 301) = -5457.93
t1 / t2 = 1
t1 - t2 = 6.18456e-011
t1 == t2 ? no
t1 / t3 = 1
t1 - t3 = 6.18456e-011
t1 == t3 ? no
t2 / t3 = 1
t2 - t3 = 0
t2 == t3 ? yes

Done.
*/

 


 

Posted by Scripter
,