양의 정수를 이진법으로 표현할 때 자리수를 구하는 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
,