Boost Library 1.75.0 을 설치하고

Visual Studio 2019 의 명령행 컴파일러 cl 로 컴파일하였다.

컴파일하기 전에 미리 환경변수 BOOST_LIB_PATH 와 MPIR_LIB_PATH 를 각각

Boost Library 와 MPIR Library 가 있는 경로로 설정해 놓아야 한다.

 

/*
 * Filename: CalculateAreaOfDiskWithBoosLibrary.cpp
 *
 *       Purpose: Test floating point numbers of arbitrary precision.
 *
 * Compile: cl CalculateAreaOfDiskWithBoosLibrary.cpp /I%BOOST_LIB_PATH% /I%MPIR_LIB_PATH% /EHsc /utf-8 MPIR_LIB_PATHmpir.lib
 * Execute: CalculateAreaOfDiskWithBoosLibrary
 *
 * Date: 2021.03.29
 * Revised Author: pkim ((AT)) scripts ((DOT)) pe ((DOT)) kr 
 *
 * See: www.boost.org/doc/libs/1_56_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/gmp_float.html
 */
 
#include<iostream>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/math/constants/constants.hpp>

using boost::multiprecision::cpp_dec_float_50;
using boost::multiprecision::cpp_dec_float_100;
using boost::multiprecision::cpp_dec_float;
using boost::multiprecision::cpp_bin_float_quad;

#include <boost/multiprecision/gmp.hpp>
using namespace boost::multiprecision;

typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<40> > flp_type_dec_40;
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<49> > flp_type_dec_49;
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<99> > flp_type_dec_99;
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<101> > flp_type_dec_101;


using namespace std;

template<typename T>
inline T area_of_a_circle(T r)
{
    // pi represent predefined constant having value
    // 3.1415926535897932384...
    using boost::math::constants::pi;
    return pi<T>() * r * r;
}



void testFloatNumbers()
{
	float radius_f = 123.0/ 100;
	float area_f = area_of_a_circle(radius_f);

	double radius_d = 123.0 / 100;
	double area_d = area_of_a_circle(radius_d);

	cpp_dec_float_50 r_mp = 123.0 / 100;
	cpp_dec_float_50 area_mp = area_of_a_circle(r_mp);

	cpp_dec_float_100  r_100 = 123.0 / 100;
	cpp_dec_float_100 area_100 = area_of_a_circle(r_100);


	cpp_bin_float_quad  r_quad= 123.0 / 100;
	cpp_bin_float_quad area_quad = area_of_a_circle(r_quad);


	flp_type_dec_40  r_40 = 123.0 / 100;
	flp_type_dec_40 area_40 = area_of_a_circle(r_40);


	flp_type_dec_49  r_49 = 123.0 / 100;
	flp_type_dec_49 area_49 = area_of_a_circle(r_49);


	flp_type_dec_99  r_99 = 123.0 / 100;
	flp_type_dec_99 area_99 = area_of_a_circle(r_99);


	flp_type_dec_101  r_101 = 123.0 / 100;
	flp_type_dec_101 area_101 = area_of_a_circle(r_101);


      using boost::math::constants::pi;
      cout << "Let be given a circle with radius, r = " << radius_d << endl;
      cout << "Calculate the area of the given circle,\n        Area = PI*r^2 = " << pi<double>() << "*" << radius_d << "^2 = " << pi<double>() << "*" << (radius_d * radius_d) << ",\nin various precisions." << endl << endl;;

	// numeric_limits::digits10 represent the number
	// of decimal digits that can be held of particular
	// data type without any loss.
	
	// Area by using float data type
	cout << " Float: "
		<< setprecision(numeric_limits<float>::digits10)
		<< area_f << endl;

	// Area by using double data type
	cout << "Double: "
		<<setprecision(numeric_limits<double>::digits10)
		<< area_d << endl;


	// Area by using Boost 40 precision Multiprecision
	cout << "Boost Multiprecision  (40 digits): "
		<< setprecision(numeric_limits<flp_type_dec_40>::digits10)
		<< area_49 << endl;

	// Area by using Boost 49 precision Multiprecision
	cout << "Boost Multiprecision  (49 digits): "
		<< setprecision(numeric_limits<flp_type_dec_49>::digits10)
		<< area_49 << endl;

	// Area by using Boost 50 precision Multiprecision
	cout << "Boost Multiprecision  (50 digits): "
		<< setprecision(numeric_limits<cpp_dec_float_50>::digits10)
		<< area_mp << endl;

	// Area by using Boost 99 precision Multiprecision
	cout << "Boost Multiprecision  (99 digits): "
		<< setprecision(numeric_limits<flp_type_dec_99>::digits10)
		<< area_99 << endl;

	// Area by using Boost 100 precidion Multiprecision
	cout << "Boost Multiprecision (100 digits): "
		<< setprecision(numeric_limits<cpp_dec_float_100>::digits10)
		<< area_100 << endl;

	// Area by using Boost 101 precision Multiprecision
	cout << "Boost Multiprecision (101 digits): "
		<< setprecision(numeric_limits<flp_type_dec_101>::digits10)
		<< area_100 << endl;

	// Area by using Boost Quaduple Multiprecision
	cout << "Boost Multiprecision  (Quadruple): "
		<< setprecision(numeric_limits<cpp_bin_float_quad>::digits10)
		<< area_quad << endl;
}


int main()
{ 
	testFloatNumbers();
	return 0;
}


/*
Output:
-------------------------------------------
Let be given a circle with radius, r = 1.23
Calculate the area of the given circle,
        Area = PI*r^2 = 3.14159*1.23^2 = 3.14159*1.5129,
in various precisions.

 Float: 4.75292
Double: 4.752915525616
Boost Multiprecision  (40 digits): 4.752915525615998053187629092943809341311
Boost Multiprecision  (49 digits): 4.752915525615998053187629092943809341310825398145
Boost Multiprecision  (50 digits): 4.7529155256159980531876290929438093413108253981451
Boost Multiprecision  (99 digits): 4.75291552561599805318762909294380934131082539814514244132288567973008216166037385350291572422559648
Boost Multiprecision (100 digits): 4.752915525615998053187629092943809341310825398145142441322885679730082161660373853502915724225596483
Boost Multiprecision (101 digits): 4.7529155256159980531876290929438093413108253981451424413228856797300821616603738535029157242255964827
Boost Multiprecision  (Quadruple): 4.75291552561599805318762909294381
-------------------------------------------
*/

 

 

 

Posted by Scripter
,

1. mpir 은 gmp 대신사용하는 (C/C++ 언어용) 긴 자리 수치 처리를 위한 기본 연산 라이브러리이다.

   자리수가 매우 긴 정수, 유리수, 소수점수를 계산할 수 있다.

2. xmpir 은 (C 언어용 긴 자리 수치 라이브러리인) mpir 의 래퍼(wrapper) 이다.

3. xmpir 은  xmpir 다운로드 에서 구할 수 있다.

(주의 사항. dl4windows.dll 파일이 존재하는 폴더의 경로명에 #문자가 있으면 컴파일은 되나 실행 시에 에러에 걸린다. 그 이유는 xmpir 이 dl4windows.dll 파일을 찾을 때 URL 주소를 적용해서 찾기 때문이다.)

 

실행에 필요한 *.dll 파일들은 (현재 경로 또는) 환경변수 PATH 에 결린 경로의 폴더에 존재해야 한다.

  • dl4windows.dll  : 윈도우 계열의 닷넷 에서 실행될 때 xmpir 이 찾는 파일
  • dl4linux.dll  : 리눅스 계열의 mono 에서 실행될 때 xmpir 이 찾는 파일
  • xmpir32.dll : 32 비트 윈도우 또는 리눅스에서 실행될 때 PATH 걸린 폴더에 있어야 하는 파일
  • xmpir64.dll : 64 비트 윈도우 또는 리눅스에서 실행될 때 PATH 걸린 폴더에 있어야 하는 파일
  • src\xmpir,cs : 컴파일할 때 함께 사용되어야 하는 파일

 

demo 폴더에서 demo,cs 컴파일하기

    Prompt> csc demo.cs ..\src\xmpir.cs

 

xmpir 을 이용하는 예제 소스 파일 (파일명: demo.cs)

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;
class MyClass
{
    [STAThread]
    static void Main(string[] args)
    {
        mpir.mpz_t f = mpir.mpz_init_set_ui(1);
        int i;
        for(i=2; i<=30; i++)
            mpir.mpz_mul_si(f, f, i);
        System.Console.Write("30! = ");
        System.Console.WriteLine(mpir.mpz_get_string(10,f));
        mpir.mpz_clear(f);        
    }
}

 

실행 결과: 30! = 265252859812191058636308480000000

 

Posted by Scripter
,

MPIR 은 Multiple Precision Integers and Rationals 은 줄인 약자로서 C 언어나 C++ 언어로 매우 긴 자리의 수치 연산을 하는 프로그램을 작성할 때 사용되는 라이브러리이다.

참고. 위키피디아의 MPIR 설명

MPIR 은 GMP 처럼 무한 자리 수치 계산을 위한 (GMP 를 대체하는) 기본 라이브러리이다. MPIR 은 정수 계산, 유리수 계산, 부동소수점수 계산은 지원하지만, 복소수 계산은 지원하지 않는다.

MPIR 은 GMP 보다 훨씬 다양한 OS 를 지원하며 CPU 에 최적화 되어있다. MPIR 은 LGPL 3 적작권으로 보호받는 소스 공개 소프트웨어이다. 상업용 패키지에 포함시킬 때는 MPIR 이 GMP 보다 라이센스 면에서 더 자유로운 것 같다.

 

다음은 MPIR 홈페이지에서 소개하는 글의 일부이다.

----------------------------------------------------

About MPIR

MPIR is an open source multiprecision integer (bignum) library forked from the GMP (GNU Multi Precision) project. It consists of much code from past GMP releases, in combination with much original contributed code. A brief introduction can be found here Introduction(French)

MPIR is constructed by a developer and vendor friendly community of professional and amateur mathematicians, computer scientists and hobbyists.

The primary goals of the MPIR project are:

  • To have a developer friendly community.
  • To foster links with hardware and software vendors.
  • Development of parallel algorithms for multiprecision arithmetic including support for GPU's and other multicore processors.
  • To provide build support out-of-the-box for Linux, Apple, Sun and Microsoft Windows systems.
  • To overall license the project with the GNU LGPL license.
  • To maintain full interface support with GMP - MPIR is a drop-in replacement for GMP.
  • Support for building MPIR using Microsoft Visual Studio 2010 for use in both 32-bit and 64-bit versions of Windows.

----------------------------------------------------

MPIR 2.6.0 이 그 이전 버전과 다른 부분은 매우 많겠지만, 우선 눈에 보이는 두 가지만 언급한다면, 하나는 64비트 CPU 와 OS 를 확실하게 지원한다는 것이고, 다른 하나는 Visual Studio 2010 에 더 쉽게 설치된다는 것이다. (하지만 안정적인 면에서는 2.6.0 보다 그 이전 버전이 좋지 않나 생각한다.)

이 글에서는 32 비트 윈도우 XP 에 cygwin 용으로, MinGW 용으로, 그리고 Visual Studio 2010 용으로 각각 빌드하여 설치하고 테스트한 결과를 남겨 두고자 한다.

 

 

1. Visual Studio 2010 에 설치하기

단계 1.  압축을 푼다.

압축 해제돤 것을 모두 폴더 D:\mpir-2.6.0 에 둔 것으로 간주하고 다음 단계를 계속 진행한다.

Visual Studio 2010 용 솔루션 파일 mpir.sln 은 폴더 D:\mpir-2.6.0\build.vc10 에 존재해야 한다.

 

단계 2.  MPIR 2.6.0 설치 과정

Visual Studio 2010 의 메뉴에서 "파일(F)" -> "열기(O)" -> "프로젝트/솔루션(P).." 를 선택하여 파일 D:\mpir-2.6.0\build.vc10\mpir.sln 을 연다.

Visual Studio 2010 의 메뉴에서 "빌드(B)" -> "구성 관리자(O)..." 를 선택한다.

아래의 그림 처럼 세 가지 항목을 선택한다. (체크박스에 체크 확인)

 

 

메뉴에서 "빌드(B)" -> "솔루션 다시 빌드(S)" 를 선택하여 (위에서 처럼) 구성관리자에서 선택햇던 항목들을 모두 빌드한다.

 

단계 3.  빌드 후 확인

dll 파일과 관련 헤더 파일은 폴더 D:\mpir-2.6.0\build.vc10\dll\Win32\Releae 에 생성되고, lib 파일과 관련 헤더 파일은 폴더 D:\mpir-2.6.0\build.vc10\lib\Win32\Releae 에 생성된다.

만일 위의 구성관리자에서 체크된 세 가지 항목을 (Release 대신) Debug 로 선택하였다면, dll 파일과 관련 헤더 파일은 폴더 D:\mpir-2.6.0\build.vc10\dll\Win32\Debug 에 생성되고, lib 파일과 관련 헤더 파일은 폴더 D:\mpir-2.6.0\build.vc10\lib\Win32\Debug 에 생성된다.

Visual Studio 2010 용으로 빌드된 mpir 은 C++ 용 라이브러리 mpirxx.lib 가 추가로 더 생성되지만, dll 파일로는 mpir.dll 만 생성된다. (mpirxx.dll 파일은 별도로 생성되지 않는다.)

 

단계 4.  MPIR 2.6.0 설치 후 테스트

아래세 제시된 C 소스와 C++ 소스를 각각 컴파일하여 실행해본다. (컴파일 명령은 각 소스의 주석문 참조)

 

 

2. cygwin 에 설치하기

단계 1.  압축을 푼다.

 

단계 2.  MPIR 2.6.0 설치 순서

아래의 configure 명령 중에 옵션 --enable-cxx CXXFLAGS=-g 이 중요하다. 이 옵션이 없으면 mpir 의 C++ 용 헤더 파일과 라이브러리가 설치되지 않는다. (Visual Studio 2010 용으로 빌드하는 것 보다는 시간이 훨씬 더 오래 걸린디.)

$ ./configure --prefix=/usr --enable-cxx CXXFLAGS=-g
$ make
$ make check
$ make install
$ make clean

설치가 성공적으로 끝나면 헤더 파일은 /usr/include 폴더에  라이브러리 파일은 /usr/lib 폴더에 생성된다.

 

 

단계 3.  MPIR 2.6.0 설치 후 테스트

아래세 제시된 C 소스와 C++ 소스를 각각 컴파일하여 실행해본다. (컴파일 명령은 각 소스의 주석문 참조)

 

 

3. MinGW 에 설치하기

단계 1.  압축을 푼다.

 

단계 2.  MPIR 2.6.0 설치 순서

아래의 configure 명령 중에 옵션 --enable-cxx CXXFLAGS=-g 이 중요하다. 이 옵션이 없으면 mpir 의 C++ 용 헤더 파일과 라이브러리가 설치되지 않는다. (Visual Studio 2010 용으로 빌드하는 것 보다는 시간이 훨씬 더 오래 걸린디.)

$ ./configure --prefix=/c/MinGW --enable-cxx CXXFLAGS=-g
$ make
$ make check
$ make install
$ make clean

설치가 성공적으로 끝나면 헤더 파일은 /c/MinGW/include 폴더에  라이브러리 파일은 /c/MinGW/lib 폴더에 생성된다.

 

단계 3.  MPIR 2.6.0 설치 후 테스트

아래세 제시된 C 소스와 C++ 소스를 각각 컴파일하여 실행해본다. (컴파일 명령은 각 소스의 주석문 참조)

 

 

4. mpir 설치 후 테스트를 위한 C 소스와 C++ 소스

 

 //  Filename: testMPIR_01.c
//
//      This has been tested with MPIR 2.5.2.
//
//   Compile: gcc -o testMPIR_01 testMPIR_01.c -lmpir
//   Execute: ./testMPIR_01
//
//    Or
//
//   Compile: cl testMPIR_01.c -I. mpir.lib
//   Execute: testMPIR_01
//
//   Date: 2013. 1. 16.
//   Copyright (c) PH Kim  ( pkim __AT__ scripts.pe.kr )

#include <stdio.h>
#include <mpir.h>

void foo (mpz_t result, const mpz_t param, int n)
{
    int i;

    mpz_mul_ui (result, param, n);
    gmp_printf ("Initialized r = %Zd\n", result);

    for (i = 1; i < n; i++) {
        mpz_add_ui (result, result, i*7);
        gmp_printf ("    r = %Zd  <--  r is added by %2d*7 = %3d\n", result, i, i*7);
    }
}


int main (void)
{
    mpz_t r, n;

    mpz_init (r);
    mpz_init_set_str (n, "123456", 0);

    mpz_set_si (r, 0);

    gmp_printf ("r = %Zd, n = %Zd\n", r, n);
    foo (r, n, 20L);
    gmp_printf ("Result is r = %Zd\n", r);

    mpz_clear(n);
    mpz_clear(r);

    return 0;
}

/*
Output:
r = 0, n = 123456
Initialized r = 2469120
    r = 2469127  <--  r is added by  1*7 =   7
    r = 2469141  <--  r is added by  2*7 =  14
    r = 2469162  <--  r is added by  3*7 =  21
    r = 2469190  <--  r is added by  4*7 =  28
    r = 2469225  <--  r is added by  5*7 =  35
    r = 2469267  <--  r is added by  6*7 =  42
    r = 2469316  <--  r is added by  7*7 =  49
    r = 2469372  <--  r is added by  8*7 =  56
    r = 2469435  <--  r is added by  9*7 =  63
    r = 2469505  <--  r is added by 10*7 =  70
    r = 2469582  <--  r is added by 11*7 =  77
    r = 2469666  <--  r is added by 12*7 =  84
    r = 2469757  <--  r is added by 13*7 =  91
    r = 2469855  <--  r is added by 14*7 =  98
    r = 2469960  <--  r is added by 15*7 = 105
    r = 2470072  <--  r is added by 16*7 = 112
    r = 2470191  <--  r is added by 17*7 = 119
    r = 2470317  <--  r is added by 18*7 = 126
    r = 2470450  <--  r is added by 19*7 = 133
Result is r = 2470450
*/

 

 

// Filename: testMPIR_02.cpp
//
//      This has been tested with MPIR 2.5.2.
//
//   Compile: g++ -o testMPIR_02 testMPIR_02.cpp -lmpirxx -lmpir
//   Execute: ./testMPIR_02
//
//    Or
//
//   Compile: cl /EHsc testMPIR_02.cpp -I. mpir.lib mpirxx.lib
//   Execute: testMPIR_02
//
//   Date: 2013. 1. 16.
//   Copyright (c) PH Kim ( pkim __AT__ scripts.pe.kr )

// #include <stdio.h>
#include <iostream>
#include <mpirxx.h>
#include <mpir.h>

using namespace std;

int main (void)
{
    mpz_class a, b, c;

    a = 1234;
    b = "-5678";
    c = a + b;

    cout << "Given two numbers are " << a << " and " << b << "." << endl;
    cout << "  Their sum is " << c << "." << endl;
    cout << "  Its absolute value is |" << a <<  " + (" << b << ")| = " << abs(c) << "." << endl;
    cout << "  Their product is " << a << "*(" << b << ") = " << (a*b) << "." << endl;

    return 0;
}

/*
Output:
Given two numbers are 1234 and -5678.
  Their sum is -4444.
  Its absolute value is |1234 + (-5678)| = 4444.
  Their product is 1234*(-5678) = -7006652.
*/

 

 

Posted by Scripter
,

아래의 소스는 윈도우에서

            Luna MinGW & GNU C 4.5.0 (gcc), 

로 테스트되었다. long 타입으로는 13! 까지만 정확하계 계산되지만 GMP 를 이용한 계산은 아무리 큰 수의 곱셈이라도 정확히 계산해준다.

  • 윈도우에 Luna MinGW (with GCC 4.5.0) 설치하기:
     1) Luna MinGW 홈페이지(MinGW GCC C/C++ Compiler package with installer) 
     2) Luna MinGW 설치파일 다운로드
  •  영문  위키피디아에서 소개하는 MinGW
  • MinGW 의 공식 웹사이트에서 MinGW 를 설치하면 gcc 버전이 3.4.5 밖에 되지 않고,
    gmp 라이브러리도 수동으로 설치헤야 하는 번거로움이 있으므로,
    여기서는 Luna MinGW 를 설치하기로 한다. Luna MinGW 를 설치하면,
    현재 최신 버전인 gcc4.5.0 을 쓸 수 있다. 그 대신 g++ 로 컴파일 후에 쓰일 런타임 다이나믹  라이브러리 libgmpxx-4.dll 은 별도로 구하여 설치해야 한다.
  • 윈도우에 Luna MinGW (with GCC 4.5.0) 설치하기:
        * Luna MinGW 홈페이지(MinGW GCC C/C++ Compiler package with installer) 
        * Luna MinGW 설치파일 다운로드
    1) 설치는 C:\MinGW 에 한것으로 간주한다.
    2) gcc 에서 gmp 라이브러리는 추가 설치 없이 바로 쓸 수 있는데,
        g++ 로는 컴파일은 되지만 컴파일된 실행파일을 실행하면 
        limgmpxx-4.dll 파일이 없다고 에러가 날 것이다. 이때는 아래 처럼 
        limgmpxx-4.dll 파일을 컴파일해서 만들던가 이미 만들어진 것을 PATH 가 걸려 있는 곳에 넣어두어야 한다. 아래는 limgmpxx-4.dll 파일을 구할 수 있는 곳이다. 
  • g++에서 gmp를 사용하기 위해 libgmpxx-4.dll 구하여 설치하기:
       * 소스포지에서 libgmpxx-5.0.1-1-mingw32-dll-4.tar.lzma 다운로드하기
    1)  확장명이 lzma 인 파일은 7zip 으로 풀어야 한다. (7zip 은 http://www.7-zip.org 에서 구한다.)
    2) 위의 파일을 받아서 7zip으로 압축 해제하여 libgmpxx-4.dll 을  C:\MinGW\bin 에 복사힌다.  (C:\MinGW 은 Luna MinGW 가 설치된 디렉토리이다)
  • gcc 버전 확인하기
    프롬프트> gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.5.0/lto-wrapper.exe
    Target: mingw32
    Configured with: ../gcc-4.5.0/configure --enable-languages=c,c++,ada,fortran,obj
    c,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgo
    mp --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific-r
    untime-libs --disable-werror --build=mingw32 --prefix=/mingw
    Thread model: win32
    gcc version 4.5.0 (GCC)
  • g++ 버전 확인하기
    프롬프트> g++ -v
    Using built-in specs.
    COLLECT_GCC=g++
    COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.5.0/lto-wrapper.exe
    Target: mingw32
    Configured with: ../gcc-4.5.0/configure --enable-languages=c,c++,ada,fortran,obj
    c,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgo
    mp --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific-r
    untime-libs --disable-werror --build=mingw32 --prefix=/mingw
    Thread model: win32
    gcc version 4.5.0 (GCC)



    * 소스 파일명: recFactGMPcpp01.cc

/*
 *  Filename: recFactGMPcpp01.cc
 *
 *  Compile: g++ -o recFactGMPcpp01 recFactGMPcpp01.cc -lgmpxx -lgmp
 */

#include <iostream>
#include <gmpxx.h>

using namespace std;

mpz_class factorial(int n) {
    static mpz_class v;
    v = 1;
    for (int i = 1; i <= n; i++) {
     v = v*i;
    }
    return v;
}

int main(int argc, char *argv[]) {
    int n1 = 9;
    int n2 = 30;
    for (int i = n1; i <= n2; i++) {
        cout << i << "! = " << factorial(i) << endl;
        if (i == 13)
            cout << "-- below calc are regular ----" << endl;
    }
    return 0;
}




실행 결과:
프롬프트> recFactGMPcpp01
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
-- below calc are regular ----
14! = 87178291200
15! = 1307674368000
16! = 20922789888000
17! = 355687428096000
18! = 6402373705728000
19! = 121645100408832000
20! = 2432902008176640000
21! = 51090942171709440000
22! = 1124000727777607680000
23! = 25852016738884976640000
24! = 620448401733239439360000
25! = 15511210043330985984000000
26! = 403291461126605635584000000
27! = 10888869450418352160768000000
28! = 304888344611713860501504000000
29! = 8841761993739701954543616000000
30! = 265252859812191058636308480000000



Posted by Scripter
,

아래의 소스는 윈도우에서

            Luna MinGW & GNU C 4.5.0 (gcc), 

로 테스트되었다. long 타입으로는 13! 까지만 정확하계 계산되지만 GMP 를 이용한 계산은 아무리 큰 수의 곱셈이라도 정확히 계산해준다.


* 소스 파일명: recFactGMP01.c

/*
 *  Filename: recFactGMP01.c
 *
 *  Compile: gcc -o recFactGMP01 recFactGMP01.c -lgmp
 */

#include <stdio.h>
#include <gmp.h>

void factorial(mpz_t v, int n) {
 int i;
    mpz_t t;
    mpz_init (t);
    mpz_init_set_str (v, "1", 0);
    for (i = 1; i <= n; i++) {
        mpz_init_set_si (t, i);
        mpz_mul(v, v, t);
    }
}

int main(int argc, char *argv[]) {
    int n1 = 9;
    int n2 = 30;
    int i;
    mpz_t v;
    mpz_init (v);
    for (i = n1; i <= n2; i++) {
        mpz_init_set_si (v, 1);
        factorial(v, i);
        gmp_printf("%d! = %Zd\n", i, v);
        if (i == 13)
        printf("-- below calc are regular ----\n");
    }
    return 0;
}



실행 결과:
프롬프트> recFactGMP01
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
-- below calc are regular ----
14! = 87178291200
15! = 1307674368000
16! = 20922789888000
17! = 355687428096000
18! = 6402373705728000
19! = 121645100408832000
20! = 2432902008176640000
21! = 51090942171709440000
22! = 1124000727777607680000
23! = 25852016738884976640000
24! = 620448401733239439360000
25! = 15511210043330985984000000
26! = 403291461126605635584000000
27! = 10888869450418352160768000000
28! = 304888344611713860501504000000
29! = 8841761993739701954543616000000
30! = 265252859812191058636308480000000



Posted by Scripter
,
GMP는 The GNU Multiple Precision Arithmetic Library(고정밀도 연산을 위한 GNU 라이브러리)의 줄임글로서 GNU MP라고도 한다. 리눅스 호환 환경이면 대부분 GMP는 이미 설치되어 있을 것이다. GMP의 공식 홈페이지는 http://gmplib.org 이고, GMP는 LGPL 하에서 배포된다.

또 gcc는 리눅스 호환 환경에서 쓸 수 있는 C 컴파일러(GNU C 컴파일러)이다. 대부분의 리눅스 호환 환경에는 gcc가  설치되어 있을 것이다.

다음 소스 코드는 GMP의 설치 테스트를 하기 위한 간단한 예제이다.

C 언어에서 GMP 라이브러리를 사용하기 위해서는 헤더 파일 gmp.h를 인클루드한다.
컴파일할 때는 반드시 컴파일 옵션 -lgmp 를 주어야 한다.
또 컴파일 옵션 -o testGMP 을 준 것은 생성될 실행파일명을 testGMP로 하라는 의미이다.
이 옵션을 생략하면 생성되는 실행파일명이 a.out(단, cygwin의 경우에는 a.exe)이다.

((  참고로, Visual C++ 6 에서 컴파일하는 명령은
           cl -I. testGMP.c /link gmp.lib /NODEFAULTLIB:LIBCMT
이다. 필자는 Visual C++ 6 에서 GMP 라이브러리를 사용하기 위해 영국에 사는 Brian Gladman 씨가 http://www.gladman.me.uk/computing/ 에서 제공하는 gmp-4.1.4.diffs.zip 을 써서 Visual C++ 6 용 GMP 라이브러리 gmp.lib 를 빌드하였다. ))

mpz_mul_ui 함수는 mpz_t 타입의 정수에 unsigned long 타입의 정수를 곱하는 함수이고,
mpz_add_ui 함수는 mpz_t 타입의 정수에 unsigned long 타입의 정수를 합하는 함수이다.

        mpz_init(r);

mpz_init 함수는 mpz_t 타입의 정수 변수를 초기화 하는 함수이다. (초기화된 값은 0)

       mpz_init_set_str(n, "123456", 10);

또 mpz_init_set_str 함수는 두번째 인수에 주어진 ASCIZ 문자열을 세 번째 인수에 주어진 적당한 진법(이 예에서는 10)을 적용하여 첫번째 인수에 주어진 mpz_t 타입의 정수 변수(이 예에서는 n)에 저장하는 함수이다.


  1. /*
  2.  *  Filename: testGMP.c
  3.  *
  4.  *   Compile: gcc -o testGMP testGMP.c -lgmp
  5.  *
  6.  *   Execute: ./testGMP
  7.  *    Output: 2470450
  8.  */
  9. #include <gmp.h>
  10. void foo(mpz_t result, const mpz_t param, unsigned long n) {
  11.     unsigned long i;
  12.     mpz_mul_ui(result, param, n);
  13.     for (i = 1; i < n; i++) {
  14.         mpz_add_ui (result, result, i*7);
  15.     }
  16. }
  17. int main(void) {
  18.     mpz_t r, n;
  19.     mpz_init(r);
  20.     mpz_init_set_str(n, "123456", 10);
  21.     foo(r, n, 20L);
  22.     gmp_printf("%Zd\n", r);
  23.     return 0;
  24. }



컴파일> gcc -o testGMP testGMP.c -lgmp

실행> ./testGMP
2470450



Win32의 Visual C++ 6 상에서 컴파일하기:
컴파일>cl -I. testGMP.c /link gmp.lib /NODEFAULTLIB:LIBCMT

실행> testGMP
2470450



Visual C++ 9.0 (Visual Studio 2008) 에서 컴파일하기:
컴파일>cl testGMP.c gmp.lib

실행> testGMP
2470450



Posted by Scripter
,