mk-mode BLOG

このブログは自作の自宅サーバに構築した Debian GNU/Linux で運用しています。
PC・サーバ構築等の話題を中心に公開しております。(クローンサイト: GitHub Pages

ブログ開設日2009-01-05
サーバ連続稼働時間
Reading...
Page View 合計
Reading...
今日
Reading...
昨日
Reading...

GMP - ソースビルドでインストール (on Linux Mint)!

[ プログラミング ] [ Ruby ]

こんにちは。

C や C++ で多倍長の数値演算を行いたく GMP ライブラリをソースビルドでインストールしてみました。

0. 前提条件

  • Linux Mint 17.1(64bit) での作業を想定しているが、 Unix 系 OS なら同様。
  • 今回はソースをビルドしてインストールする。
  • C だけでなく C++ でも使用可能となるようにする。
  • 今回の動作確認は整数に関してのみ行なう。

1. GMP とは

  • The GNU Multi Precision Arithmetic Library の略
  • 符号付き整数や有理数、浮動小数を任意精度で扱うための算術ライブラリ
  • GNU プロジェクトの一部

2. アーカイブの取得&展開

最新の “tar.bz2” ファイルをダウンロードする。("tar.lz", “tar.xz” でもよい。但し、"tar.lz" の展開には lzip コマンドが必要)

1
2
$ wget https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2
$ tar jxvf gmp-6.0.0a.tar.bz2

3. ビルド&インストール

以下の手順でビルド&インストールする。(C++ に対応するために configure--enable-cxx オプションを付加)

1
2
3
4
5
$ cd 6.0.0
$ ./configure --enable-cxx
$ make
$ make check
$ sudo make install

/usr/local/lib にインストールされる。

4. 動作確認用 C, C++ ソースコードの作成

動作確認用の C ソースコードを作成する。

test_gmp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*************************************************************
 * GMP(The GNU Multi Presicion Arithmetic Library) Test by C.
 ************************************************************/
#include <gmp.h>

int main(int argc, char *argv[])
{
    // Declaration
    mpz_t op1, op2, op3, op5, op6, op7, op8;  // GMP Integer
    mpz_t rop, rop2;                          // GMP Integer
    unsigned int op4;                         // Unsigned integer

    // Initialization
    op4 = 100;
    mpz_init(op1);
    mpz_init(op2);
    mpz_init(op3);
    mpz_init(op5);
    mpz_init(op6);
    mpz_init(op7);
    mpz_init(op8);
    mpz_init(rop);
    mpz_init(rop2);
    mpz_set_ui(op1, 123456789);   // GMP Unsigned integer
    mpz_set_ui(op2, 987654);      // GMP Unsigned integer
    mpz_set_ui(op3, 2);           // GMP Unsigned integer
    mpz_set_ui(op5, op4);         // GMP Unsigned integer
    mpz_set_ui(op6, 123456789);   // GMP Unsigned integer
    mpz_set_ui(op7, 987654);      // GMP Unsigned integer
    mpz_set_si(op8, -999999999);  // GMP Signed integer

    // Addition
    mpz_add(rop, op1, op2);
    gmp_printf("%Zd + %Zd = %Zd\n", op1, op2, rop);

    // Subtraction
    mpz_sub(rop, op1, op2);
    gmp_printf("%Zd - %Zd = %Zd\n", op1, op2, rop);

    // Multiplication
    mpz_mul(rop, op1, op2);
    gmp_printf("%Zd * %Zd = %Zd\n", op1, op2, rop);

    // Multiplication & addition
    mpz_addmul(rop, op2, op3);
    gmp_printf("+ %Zd * %Zd = %Zd\n", op2, op3, rop);

    // Multiplication & subtraction
    mpz_submul(rop, op2, op3);
    gmp_printf("- %Zd * %Zd = %Zd\n", op2, op3, rop);

    // Division(Remaider)
    mpz_cdiv_q(rop, op6, op7);
    gmp_printf("%Zd / %Zd = %Zd\n", op6, op7, rop);
    mpz_cdiv_qr(rop, rop2, op6, op7);
    gmp_printf("%Zd / %Zd = %Zd ... %Zd\n", op6, op7, rop, rop2);
    mpz_fdiv_q(rop, op6, op7);
    gmp_printf("%Zd / %Zd = %Zd\n", op6, op7, rop);
    mpz_fdiv_qr(rop, rop2, op6, op7);
    gmp_printf("%Zd / %Zd = %Zd ... %Zd\n", op6, op7, rop, rop2);
    mpz_tdiv_q(rop, op6, op7);
    gmp_printf("%Zd / %Zd = %Zd\n", op6, op7, rop);
    mpz_tdiv_qr(rop, rop2, op6, op7);
    gmp_printf("%Zd / %Zd = %Zd ... %Zd\n", op6, op7, rop, rop2);

    // Modulo
    mpz_mod(rop, op6, op7);
    gmp_printf("%Zd mod %Zd = %Zd\n", op6, op7, rop);

    // Left shift
    mpz_mul_2exp(rop, op3, op4);
    gmp_printf("%Zd << %d = %Zd\n", op3, op4, rop);

    // Power
    mpz_pow_ui(rop, op3, op4);
    gmp_printf("%Zd ^ %d = %Zd\n", op3, op4, rop);

    // Power and modulo
    mpz_powm(rop, op3, op5, op6);
    gmp_printf("(%Zd ^ %Zd) mod %Zd = %Zd\n", op3, op5, op6, rop);

    // Negative value (Sign inversion)
    mpz_neg(rop, op1);
    gmp_printf("%Zd * (-1) = %Zd\n", op1, rop);

    // Absolute value
    mpz_abs(rop, op8);
    gmp_printf("abs(%Zd) = %Zd\n", op8, rop);

    // Square root
    mpz_sqrt(rop, op1);
    gmp_printf("sqrt(%Zd) = %Zd\n", op1, rop);
    mpz_sqrtrem(rop, rop2, op1);
    gmp_printf("sqrt(%Zd) = %Zd ... %Zd\n", op1, rop, rop2);

    // Deallocation
    mpz_clear(op1);
    mpz_clear(op2);
    mpz_clear(op3);
    mpz_clear(op5);
    mpz_clear(op6);
    mpz_clear(op7);
    mpz_clear(op8);
    mpz_clear(rop);

    return 0;
}

(除算・剰余で使用している cdivc は ceil の略で小数点以下切り上げ、fdivf は floor の略で整数部分のみ、tdivt は truncate の略で小数点以下切り捨てという意味)

上記の他に、素数、最大公約数、最小公倍数、ヤコビ、ルシャンドル、クロネッカー、フィボナッチ、値の比較、論理演算・ビット演算等々、様々な関数が用意されている。

同様に、動作確認用の C++ ソースコードを作成する。C と同様の記述も可能だが C++ 用にラップされた記述方法で作成する。(除算&剰余、べき乗&剰余等は個別に工夫すればよいので省略)

test_gmp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/***************************************************************
 * GMP(The GNU Multi Presicion Arithmetic Library) Test by C++.
 **************************************************************/
#include <iostream>  // for cout
#include <gmp.h>
#include <gmpxx.h>

using namespace std;

class TestGmp
{
    // Declaration
    mpz_class op1, op2, op3, op5, op6, op7;  // GMP Integer
    mpz_class rop;                           // GMP Integer
    unsigned int op4;                        // Unsigned integer

public:
    TestGmp();        // Constructor
    void execTest();  // Execute test
};

/*
 * Constructor
 */
TestGmp::TestGmp()
{
    // Initialization
    op1 = 123456789;   // GMP Integer
    op2 = 987654;      // GMP Integer
    op3 = 2;           // GMP Integer
    op4 = 100;         // Unsigned integer
    op5 = 123456789;   // GMP Integer
    op6 = 987654;      // GMP Integer
    op7 = -999999999;  // GMP Integer
}

/*
 * Execute test
 */
void TestGmp::execTest()
{
    // Addition
    rop = op1 + op2;
    cout << op1 << " + " << op2 << " = " << rop << endl;

    // Subtraction
    rop = op1 - op2;
    cout << op1 << " - " << op2 << " = " << rop << endl;

    // Multiplication
    rop = op1 * op2;
    cout << op1 << " * " << op2 << " = " << rop << endl;

    // Division(Remaider)
    rop = op5 / op6;
    cout << op5 << " / " << op6 << " = " << rop << endl;

    // Modulo
    rop = op5 % op6;
    cout << op5 << " % " << op6 << " = " << rop << endl;

    // Left shift
    rop = op3 << op4;
    cout << op3 << " << " << op4 << " = " << rop << endl;

    // Absolute value
    rop = abs(op7);
    cout << "abs(" << op7 << ") = " << rop << endl;

    // Square root
    rop = sqrt(op1);
    cout << "sqrt(" << op1 << ") = " << rop << endl;
}

int main()
{
    try
    {
        // Instantiation
        TestGmp objGmp;

        // Execute test
        objGmp.execTest();
    }
    catch (...) {
        cout << "ERROR!" << endl;
        return -1;
    }

    return 0;
}

5. C, C++ ソースコードのコンパイル

-Wall は警告も出力するオプション、-O2 は最適化のオプション、-lgmp は GMP ライブラリを読み込むオプション。
-lgmp は最後に指定する。

1
2
3
$ gcc -Wall -O2 -o test_gmp_c test_gmp.c -lgmp

$ g++ -Wall -O2 -o test_gmp_cpp test_gmp.cpp -lgmp -lgmpxx

6. 動作確認

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ ./text_gmp_c
123456789 + 987654 = 124444443
123456789 - 987654 = 122469135
123456789 * 987654 = 121932591483006
+ 987654 * 2 = 121932593458314
- 987654 * 2 = 121932591483006
123456789 / 987654 = 126
123456789 / 987654 = 126 ... -987615
123456789 / 987654 = 125
123456789 / 987654 = 125 ... 39
123456789 / 987654 = 125
123456789 / 987654 = 125 ... 39
123456789 mod 987654 = 39
2 << 100 = 2535301200456458802993406410752
2 ^ 100 = 1267650600228229401496703205376
(2 ^ 100) mod 123456789 = 83598172
123456789 * (-1) = -123456789
abs(-999999999) = 999999999
sqrt(123456789) = 11111
sqrt(123456789) = 11111 ... 2468

$ ./text_gmp_cpp
123456789 + 987654 = 124444443
123456789 - 987654 = 122469135
123456789 * 987654 = 121932591483006
123456789 / 987654 = 125
123456789 % 987654 = 39
2 << 100 = 2535301200456458802993406410752
abs(-999999999) = 999999999
sqrt(123456789) = 11111

参考サイト

(ドキュメントは GNU MP 6.0.0


整数以外に有理数や浮動小数についても理解すると、数値計算を行う際に威力を発揮することでしょう。

以上。

Comments