はじめに

編集

GNU Multi-Precision Libraryについて

編集

GNU Multi-Precision Library (GMP) は、多倍長整数、有理数、浮動小数点数の演算をサポートするための高速で信頼性の高いライブラリです。GMPはC言語で記述されており、GNU Lesser General Public License(LGPL)の下でリリースされています。GMPは、高速なプラットフォームに特化した数値計算アルゴリズムを使用して、数百桁から数百万桁にも及ぶ数値計算を可能にします。

GMPは、C言語で数学的なアルゴリズムを実装する必要がある多くのアプリケーションで使用されています。例えば、暗号化、符号化、ハッシュ関数、特定のアルゴリズムに基づく素因数分解、多項式の因数分解などです。

インストール方法の紹介

編集

GMPをインストールするには、以下の手順を実行します。

GMPのウェブサイト( https://gmplib.org/ )から最新の安定版をダウンロードします。

tarコマンドを使用して、ダウンロードしたアーカイブを解凍します。例えば、以下のようにします。

% tar -xzvf gmp-x.y.z.tar.gz

展開したディレクトリに移動します。

% cd gmp-x.y.z

GMPをビルドします。

% ./configure
% make

GMPをインストールします。

% make install

これで、GMPがシステムにインストールされます。

基本的な使い方

編集

GMPのデータ型と初期化方法

編集

GMPは複数の整数の型をサポートしており、各型に対して適切な初期化が必要です。

まず、最も一般的な型である mpz_t (多倍長整数型)を初期化する方法を示します。

#include <gmp.h>

int main() {
  mpz_t n;
  mpz_init(n); // 変数nを0で初期化

  // 変数nに値を代入
  mpz_set_ui(n, 123456789);

  // 変数nの値を表示
  gmp_printf("n = %Zd\n", n);

  // 変数nを解放
  mpz_clear(n);
}

mpz_t 変数は mpz_init によって0で初期化されます。次に、mpz_set_ui を使用して変数に値を代入します。mpz_set_ui は、unsigned long型の整数を受け取り、それを mpz_t 変数に代入します。mpz_set を使用することで、mpz_t 変数に他の mpz_t 変数の値を代入することもできます。

gmp_printf 関数は、GMPの printf 関数です。%Zdmpz_t 型を出力するためのフォーマット文字列です。

最後に、mpz_clear 関数を使用して mpz_t 変数を解放します。

mpz_t 以外にも、mpq_t(多倍長有理数型)、mpf_t(多倍長浮動小数点数型)などがあり、それぞれ適切な初期化方法が必要です。

コンパイル

編集

GMPを使ったプログラムをコンパイルするには、GMPをインストールしたディレクトリの場所をコンパイラに伝える必要があります。このためには、コンパイラオプションに-Iオプションを指定してGMPのincludeディレクトリの場所を指定し、リンカオプションに-Lオプションを指定してGMPのライブラリの場所を指定します。

例えば、以下のようなコンパイルオプションを使用して、test.cというファイルをコンパイルすることができます。

% cc -I/usr/local/include -L/usr/local/lib -lgmp test.c -o test

ここでは、-Iオプションで/usr/local/includeを、-Lオプションで/usr/local/libを指定しています。-lgmpは、GMPのライブラリを指定しています。-oオプションで、コンパイルしたプログラムの実行ファイル名を指定しています。

整数の操作

編集

加算、減算、乗算、除算、余り

編集

GMPライブラリは、整数の加算、減算、乗算、除算、余りを計算するための関数を提供しています。

void mpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2);
void mpz_sub (mpz_t rop, const mpz_t op1, const mpz_t op2);
void mpz_mul (mpz_t rop, const mpz_t op1, const mpz_t op2);
void mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d);
void mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d);

これらの関数は、mpz_t型の整数変数を引数に取ります。例えば、2つの整数変数x、yの和を計算し、zに格納する場合は以下のようにします。

mpz_t x, y, z;
mpz_init(x);
mpz_init(y);
mpz_init(z);
mpz_set_ui(x, 1234);
mpz_set_ui(y, 5678);
mpz_add(z, x, y);
gmp_printf("x + y = %Zd\n", z);

また、mpz_tdiv_q関数とmpz_tdiv_r関数は、それぞれ除算の商と余りを計算します。例えば、整数aを整数bで除算し、商をq、余りをrに格納する場合は以下のようにします。

mpz_t a, b, q, r;
mpz_init(a);
mpz_init(b);
mpz_init(q);
mpz_init(r);
mpz_set_ui(a, 123456789);
mpz_set_ui(b, 987654321);
mpz_tdiv_qr(q, r, a, b);
gmp_printf("%Zd / %Zd = %Zd ... %Zd\n", a, b, q, r);

以上が、GMPライブラリを使用して整数の加算、減算、乗算、除算、余りを計算する方法です。

浮動小数点数の操作

編集

加算、減算、乗算、除算、平方根、指数関数、対数関数

編集

浮動小数点数の操作も GNU MPFR ライブラリを使用して行うことができます。例えば、2つの浮動小数点数の加算、減算、乗算、除算、平方根、指数関数、対数関数を計算することができます。

#include <stdio.h>
#include <stdlib.h>
#include <mpfr.h>

int main(void)
{
    mpfr_t a, b, c, d, e, f, g;

    // 初期化
    mpfr_init2(a, 256);
    mpfr_init2(b, 256);
    mpfr_init2(c, 256);
    mpfr_init2(d, 256);
    mpfr_init2(e, 256);
    mpfr_init2(f, 256);
    mpfr_init2(g, 256);

    // 浮動小数点数の代入
    mpfr_set_str(a, "1.23456789", 10, MPFR_RNDN);
    mpfr_set_str(b, "9.87654321", 10, MPFR_RNDN);

    // 加算
    mpfr_add(c, a, b, MPFR_RNDN);

    // 減算
    mpfr_sub(d, a, b, MPFR_RNDN);

    // 乗算
    mpfr_mul(e, a, b, MPFR_RNDN);

    // 除算
    mpfr_div(f, a, b, MPFR_RNDN);

    // 平方根
    mpfr_sqrt(g, a, MPFR_RNDN);

    // 指数関数
    mpfr_exp(g, a, MPFR_RNDN);

    // 対数関数
    mpfr_log(g, a, MPFR_RNDN);

    // 結果の出力
    printf("a + b = ");
    mpfr_out_str(stdout, 10, 0, c, MPFR_RNDN);
    printf("\n");

    printf("a - b = ");
    mpfr_out_str(stdout, 10, 0, d, MPFR_RNDN);
    printf("\n");

    printf("a * b = ");
    mpfr_out_str(stdout, 10, 0, e, MPFR_RNDN);
    printf("\n");

    printf("a / b = ");
    mpfr_out_str(stdout, 10, 0, f, MPFR_RNDN);
    printf("\n");

    printf("sqrt(a) = ");
    mpfr_out_str(stdout, 10, 0, g, MPFR_RNDN);
    printf("\n");

    printf("exp(a) = ");
    mpfr_out_str(stdout, 10, 0, g, MPFR_RNDN);
    printf("\n");

    printf("log(a) = ");
    mpfr_out_str(stdout, 10, 0, g, MPFR_RNDN);
    printf("\n");

    // 終了処理
    mpfr_clear(a);
    mpfr_clear(b);
    mpfr_clear(c);
    mpfr_clear(d);
    mpfr_clear(e);
    mpfr_clear(f);
    mpfr_clear(g);

    return 0;
}

このプログラムは、GNU Multi-Precision Libraryを使って浮動小数点数の加算、減算、乗算、除算、平方根、指数関数、対数関数を計算する例です。

まず、mpfr_tという構造体型の変数a, b, c, d, e, f, gを宣言します。これらは、それぞれの演算に使用する浮動小数点数を表します。

次に、mpfr_init2()関数を使って、各変数を初期化します。この関数は、初期化する変数と精度(ビット数)を引数に取ります。この例では、すべての変数を256ビットで初期化しています。

mpfr_set_str()関数を使って、変数aとbに値を代入します。この関数は、代入する変数、文字列として表された値、基数(ここでは10進数)、および丸めモード(ここでは「最近接偶数丸め」)を引数に取ります。

それぞれの演算は、mpfr_add()、mpfr_sub()、mpfr_mul()、mpfr_div()、mpfr_sqrt()、mpfr_exp()、mpfr_log()関数を使って計算されます。これらの関数は、演算結果を代入する変数、演算に使用する変数、および丸めモードを引数に取ります。

次に、mpfr_out_str()関数を使って、演算結果を出力します。この関数は、出力するファイルストリーム、基数、小数点以下の桁数、出力する変数、および丸めモードを引数に取ります。

最後に、mpfr_clear()関数を使って、各変数を解放してプログラムを終了します。

比較演算

編集

等しいかどうか、大小比較

編集

GNU Multi-Precision Libraryにおいて、浮動小数点数の等しいかどうか、大小比較を行うためには、以下の関数を使用します。

  • int mpfr_cmp(mpfr_t op1, mpfr_t op2): op1op2を比較し、op1op2より大きければ正の値、等しければ0、小さければ負の値を返します。例えば、mpfr_cmp(a, b)は、abよりも大きい場合に正の値、等しい場合に0、小さい場合に負の値を返します。
  • int mpfr_equal_p(mpfr_t op1, mpfr_t op2): op1op2が等しい場合に非ゼロ値(真)を返し、等しくない場合にゼロ(偽)を返します。

これらの関数は、mpfr_t型の変数を引数として取り、比較には丸めモードが使用されます。

例えば、以下のコードは、abが等しい場合には"equal"、abより大きい場合には"greater than"、abより小さい場合には"less than"という文字列を出力します。

if (mpfr_cmp(a, b) == 0) {
    printf("equal\n");
} else if (mpfr_cmp(a, b) > 0) {
    printf("greater than\n");
} else {
    printf("less than\n");
}

また、以下のコードは、abが等しい場合には"equal"、等しくない場合には"not equal"という文字列を出力します。

if (mpfr_equal_p(a, b)) {
    printf("equal\n");
} else {
    printf("not equal\n");
}

応用例

編集

素数判定

編集

階乗計算

編集

行列計算

編集

パフォーマンスの最適化

編集

逆数の計算方法

編集

乗算アルゴリズムの最適化

編集

GMPの高度な機能

編集

多倍長整数による暗号技術の実装

編集

多倍長浮動小数点数による科学技術計算

編集

まとめ

編集

GMPの利点と欠点

編集

今後の展望

編集