カテゴリー別アーカイブ: GMP

応用作品

 GMPもMPFRもとても有用なライブラリですが,使い方に関して言うと「ちょっと煩わしい」感じがします.そこで,当ゼミではこれらライブラリをちょっと使いやすくするための一種の「ラッパー」みたいなものをC++言語で記述して使っています.
 
これはC++で高精度演算をするための関数群を提供するヘッダファイル “bignum.h” として実装したもの(下記)です.

作品:bignum.h
 まだまだツッコミどころのあるコードですが,計算が便利になっています.(^^)
 
【bignum.hの使い方】
 bignum.hは高精度演算のための2つのクラス(下記)を提供します.
 
1) BigQ : 計算精度を落とさずに算術演算(加減乗除)を行うためのクラス
2) BigF : 指定した精度(ビット長)で算術演算と各種関数の計算を行うためのクラス
 
基本的な使い方を例を挙げて説明します.

Step-1: オブジェクトの宣言
例: BigF pi(332), c3(332), x(332), y(332);
 これで332ビット(10進数で約100桁)の精度を持つ4つの変数(オブジェクト)pi,c3,x,yが生成されます.
 
Step-2: 値の設定
例: c3 = 3;
 これでc3に3が代入されます.オブジェクトを宣言する時に値を代入することもできます.
 (例えば,BigF c3(3,332); )
 
Step-3: 計算の実行
例: pi.setPi();
 これでpiに円周率が代入されます.
 
Step-4: 値の出力
例: pi.toString(s);
   printf(“pi: %s\n\n”,s);
 これでpiの内容が文字列としsに格納されます.
 
プログラム例: π,cos(π),π/3,cos(π/3)を求めるプログラム

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
#include	<iostream>
#include	"bignum.h"
 
int main()
{
	char	*s;
	s = (char*)malloc(1048576);
 
	BigF	pi(332), c3(332), x(332), y(332);
 
	c3 = 3;
 
	pi.setPi();
	pi.toString(s);
	printf("pi: %s\n\n",s);
 
	y.setCos(pi);
	y.toString(s);
	printf("y=cos(pi): %s\n\n",s);
 
	x.setDiv(pi,c3);
	x.toString(s);
	printf("pi/3: %s\n\n",s);
 
	y.setCos(x);
	y.toString(s);
	printf("y=cos(pi/3): %s\n",s);
}

実行結果

pi: 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170678
 
y=cos(pi): -1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 
pi/3: 1.0471975511965977461542144610931676280657231331250352736583148641026054687620696662093449417807056892
 
y=cos(pi/3): 0.50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011

※ 末の桁の誤差に注意してください.
 
=== 簡易リファレンス ===

【有理数クラス:BigQ】
■ オブジェクトの生成
BigQ x 初期値なし
BigQ x(値) 生成時に初期値(値)を設定する.
■ オブジェクトの廃棄
x.Free() BigQ型のオブジェクトxを廃棄する.
■ C言語の基本的な値の代入
x = 値 BigQ型のオブジェクトxに値を代入する.
■ C言語の変数への変換
x.toInt() BigQ型のオブジェクトxをint型の値に変換したものを返す.
x.toLong() BigQ型のオブジェクトxをlong型の値に変換したものを返す.
x.toDouble() BigQ型のオブジェクトxをdouble型の値に変換したものを返す.
x.toString(s) BigQ型のオブジェクトxを文字列(char *s)に変換する.
■ 演算
x.setAdd(v1,v2) v1+v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setSub(v1,v2) v1-v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setMul(v1,v2) v1*v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setDiv(v1,v2) v1/v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setAdd(v) BigQ型のオブジェクトxにBigQ型のオブジェクトvの値を加算する.(計算結果はxの値になる)
x.setSub(v) BigQ型のオブジェクトxからBigQ型のオブジェクトvの値を引く.(計算結果はxの値になる)
x.setMul(v) BigQ型のオブジェクトxにBigQ型のオブジェクトvの値を掛ける.(計算結果はxの値になる)
x.setDiv(v) BigQ型のオブジェクトxをBigQ型のオブジェクトvの値で割る.(計算結果はxの値になる)
x.setNeg(v) BigQ型のオブジェクトvの符号を反転した値をxに代入する.
x.setInv(v) BigQ型のオブジェクトvの逆数をxに代入する.
x.setPow(v,p) BigQ型のオブジェクトvのp乗をxに代入する.(unsigned long p)
x.setInc() xの値を1増やす.
x.setDec() xの値を1減らす.
x.setFact(n) nの階乗をxに代入する.(unsigned long n)
■ 述語(比較など)
x == y BigQ型のオブジェクトx,yの値が等しければtrue,それ以外はfalseを返す.
x != y BigQ型のオブジェクトx,yの値が異なればtrue,それ以外はfalseを返す.
x > y BigQ型のオブジェクトx,yの値を比較し,x>yならばtrue,それ以外はfalseを返す.
x < y BigQ型のオブジェクトx,yの値を比較し,x
x >= y BigQ型のオブジェクトx,yの値を比較し,x>=yならばtrue,それ以外はfalseを返す.
x <= y BigQ型のオブジェクトx,yの値を比較し,x<=yならばtrue,それ以外はfalseを返す.

 

【浮動小数点数クラス:BigF】
■ オブジェクトの生成
BigF x デフォルト精度で生成する.
BigF x(精度) 生成時に精度(ビット長)を設定する.
BigF x(値,精度) 生成時に初期値(値)と精度(ビット長)を設定する.
■ オブジェクトの精度の変更
x.setPrec(精度) BigF型オブジェクトxの精度(ビット長)を変更(再設定)する.
■ オブジェクトの廃棄
x.Free() BigF型のオブジェクトxを廃棄する.
■ C言語の基本的な値の代入
x = 値 BigF型のオブジェクトxに値を代入する.
■ C言語の変数への変換
x.toInt() BigF型のオブジェクトxをint型の値に変換したものを返す.
x.toLong() BigF型のオブジェクトxをlong型の値に変換したものを返す.
x.toDouble() BigF型のオブジェクトxをdouble型の値に変換したものを返す.
x.toString(s) BigF型のオブジェクトxを文字列(char *s)に変換する.
■ C言語の基本的な値の代入
x = 値 BigF型のオブジェクトxに値を代入する.
■ 特殊な値の代入
x.setZero(符号) BigF型のオブジェクトxに0を代入する.符号はint型で,正なら+0を,負なら-0を,0なら0を設定する.
x.setInf(符号) BigF型のオブジェクトxに無限大を代入する.符号はint型で,正なら+∞を,負なら-∞を,0なら∞を設定する.
x.setNan() BigF型のオブジェクトxにNan(Not a number)を設定する.
■ 基本的な演算
x.setAdd(v1,v2) v1+v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setSub(v1,v2) v1-v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setMul(v1,v2) v1*v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setDiv(v1,v2) v1/v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setAdd(v) BigF型のオブジェクトxにBigF型のオブジェクトvの値を加算する.(計算結果はxの値になる)
x.setSub(v) BigF型のオブジェクトxからBigF型のオブジェクトvの値を引く.(計算結果はxの値になる)
x.setMul(v) BigF型のオブジェクトxにBigF型のオブジェクトvの値を掛ける.(計算結果はxの値になる)
x.setDiv(v) BigF型のオブジェクトxをBigF型のオブジェクトvの値で割る.(計算結果はxの値になる)
x.setNeg(v) BigF型のオブジェクトvの符号を反転した値をxに代入する.
x.setInv(v) BigF型のオブジェクトvの逆数をxに代入する.
x.setAbs(v) BigF型のオブジェクトvの絶対値をxに代入する.
x.setPow(v,p) BigF型のオブジェクトvのp乗をxに代入する.(unsigned long p)
x.setFact(n) nの階乗をxに代入する.(nはint,long,unsigned long)
■ 関数
x.setSqrt(v) BigF型のオブジェクトvの平方根をxに代入する.
x.setPi() 円周率をxに代入する.
x.setExp(v) e^v(vはBigF型)の値をxに代入する.
x.setExp2(v) 2^v(vはBigF型)の値をxに代入する.
x.setExp10(v) 10^v(vはBigF型)の値をxに代入する.
x.setLog(v) BigF型のオブジェクトvの対数(底e)をxに代入する.
x.setLog2(v) BigF型のオブジェクトvの対数(底2)をxに代入する.
x.setLog10(v) BigF型のオブジェクトvの対数(底10)をxに代入する.
x.setSin(v) 正弦関数sin(v)(vはBigF型)の値をxに代入する.
x.setCos(v) 余弦関数cos(v)(vはBigF型)の値をxに代入する.
x.setTan(v) 正接関数tan(v)(vはBigF型)の値をxに代入する.
x.setSec(v) 正割関数sin(v)(vはBigF型)の値をxに代入する.
x.setCsc(v) 余割関数cos(v)(vはBigF型)の値をxに代入する.
x.setCot(v) 余接関数tan(v)(vはBigF型)の値をxに代入する.
x.setAsin(v) 逆正弦関数asin(v)(vはBigF型)の値をxに代入する.
x.setAcos(v) 逆余弦関数acos(v)(vはBigF型)の値をxに代入する.
x.setAtan(v) 逆正接関数atan(v)(vはBigF型)の値をxに代入する.
x.setSinh(v) 双曲線関数sinh(v)(vはBigF型)の値をxに代入する.
x.setCosh(v) 双曲線関数cosh(v)(vはBigF型)の値をxに代入する.
x.setTanh(v) 双曲線関数tanh(v)(vはBigF型)の値をxに代入する.
x.setSech(v) 双曲線関数sech(v)(vはBigF型)の値をxに代入する.
x.setCsch(v) 双曲線関数csch(v)(vはBigF型)の値をxに代入する.
x.setCoth(v) 双曲線関数coth(v)(vはBigF型)の値をxに代入する.
x.setAsinh(v) 逆双曲線関数sinh(v)(vはBigF型)の値をxに代入する.
x.setAcosh(v) 逆双曲線関数cosh(v)(vはBigF型)の値をxに代入する.
x.setAtanh(v) 逆双曲線関数tanh(v)(vはBigF型)の値をxに代入する.
x.setGamma(v) ガンマ関数Γ(v)(vはBigF型)の値をxに代入する.
x.setZeta(v) ゼータ関数Ζ(v)(vはBigF型)の値をxに代入する.
■ 述語(比較など)
x == y BigF型のオブジェクトx,yの値が等しければtrue,それ以外はfalseを返す.
x != y BigF型のオブジェクトx,yの値が異なればtrue,それ以外はfalseを返す.
x > y BigF型のオブジェクトx,yの値を比較し,x>yならばtrue,それ以外はfalseを返す.
x < y BigF型のオブジェクトx,yの値を比較し,x
x >= y BigF型のオブジェクトx,yの値を比較し,x>=yならばtrue,それ以外はfalseを返す.
x <= y BigF型のオブジェクトx,yの値を比較し,x<=yならばtrue,それ以外はfalseを返す.
x.isZero(符号) BigF型のオブジェクトxがゼロならばtrue,それ以外はfalseを返す.符号はint型で,正ならば+0,負ならば-0,0ならば0であることを判定する.
x.isInf(符号) BigF型のオブジェクトxが無限大ならばtrue,それ以外はfalseを返す.符号はint型で,正ならば+∞,負ならば-∞,0ならば∞であることを判定する.

MPFRの利用

 GMP(Gnu MP)は基本的には算術(加減乗除)の演算のみを提供しますが,各種の高度な関数(指数関数,対数関数,三角関数など)の値を計算するための機能はありません.そこで,GMPを利用して高度な関数を計算するためのライブラリ MPFR が作られました.
 
GNU MPFRのサイト: http://www.mpfr.org/
 
 MPFRの使い方はGMPに倣っており,mpfr_t 型のオブジェクトを用いて計算処理を実行します.MPFR用の各種関数もGMPのものと類似しており,同じような使い方ができます.
 
【各種計算のための関数】 (一部の代表的なもの)

算術演算 書式 意味
加算 mpfr_add(x,a,b,丸め指定) x = a + b
減算 mpfr_sub(x,a,b,丸め指定) x = a – b
乗算 mpfr_mul(x,a,b,丸め指定) x = a * b
除算 mpfr_div(x,a,b,丸め指定) x = a / b
べき乗 mpfr_pow(x,a,b,丸め指定) x = a ^ b
指数・対数関数 書式 意味
e^n mpfr_exp(x,n,丸め指定) x = e ^ n
2^n mpfr_exp2(x,n,丸め指定) x = 2 ^ n
10^n mpfr_exp10(x,n,丸め指定) x = 10 ^ n
log e n mpfr_log(x,n,丸め指定) x = log e n
log 2 n mpfr_log2(x,n,丸め指定) x = log 2 n
log 10 n mpfr_log10(x,n,丸め指定) x = log 10 n
三角関数 書式 意味
正弦関数 mpfr_sin(y,x,丸め指定) y = sin(x)
余弦関数 mpfr_cos(y,x,丸め指定) y = cos(x)
正接関数 mpfr_tan(y,x,丸め指定) y = tan(x)
逆正弦関数 mpfr_asin(y,x,丸め指定) y = asin(x)
逆余弦関数 mpfr_acos(y,x,丸め指定) y = acos(x)
逆正接関数 mpfr_atan(y,x,丸め指定) y = atan(x)

GMP利用の流れ

1) 値を保持するオブジェクトの宣言
 値を保持するオブジェクトには mpz_t(整数型)mpq_t(有理数型)mpf_t(浮動小数点数型)の3つがあり,必要に応じてそれらの型のオブジェクトを宣言します.
 
例.有理数型のオブジェクトの宣言: mpq_t a, b, c;
 
2) オブジェクトの初期化
 GMPのオブジェクトは計算に使用する前(値を格納する前)に初期化処理をする必要があります.
 
例.有理数型オブジェクトの初期化:
 mpq_init(a);
 mpq_init(b);
 mpq_init(c);

同様に mpz_init, mpf_init 関数があります.
 
3) オブジェクトへの値の格納(代入)
■ mpz_t(整数)オブジェクト x への値の格納
 mpz_set_ui( mpz_t x, unsigned long v ) : 符号なしlong型のvを代入
 mpz_set_si( mpz_t x, long v ) : long型のvを代入
 mpz_set_str( mpz_t x, const char *v, inv base ) :
   base進法の基数で表現された文字列としての整数vを解釈して代入
 
■ mpq_t(有理数)オブジェクト x への値の格納
 mpq_set_ui( mpz_t x, unsigned long v1, unsigned long v2 ) :
   符号なしlong型で表現された有理数 v1/v2 を代入
 mpq_set_si( mpz_t x, long v1, unsigned long v2 ) :
   同じく v1/v2 を代入
 mpq_set_d( mpz_t x, double v ) : double型の v を代入
 mpq_set_str( mpz_t x, const char *v, inv base ) :
   base進法の基数で表現された文字列としての有理数vを解釈して代入

同様に mpf_t 型のオブジェクトにも値を格納する関数があります.
 
4) 計算処理
■ 加算: r = v1 + v2
 mpz_add(r,v1,v2), mpq_add(r,v1,v2), mpf_add(r,v1,v2)
■ 減算: r = v1 – v2
 mpz_sub(r,v1,v2), mpq_sub(r,v1,v2), mpf_sub(r,v1,v2)
■ 乗算: r = v1 * v2
 mpz_mul(r,v1,v2), mpq_mul(r,v1,v2), mpf_mul(r,v1,v2)
■ 除算: r = v1 / v2
 mpz_div(r,v1,v2), mpq_div(r,v1,v2), mpf_div(r,v1,v2)
その他…
 
5) 出力(変換)
■ 文字列への変換
例.mpz_t(整数型)のオブジェクト x を char *s に変換する
 mpz_get_str( char *s, int base, mpz_t x )
同様に mpq_t, mpf_t 型のオブジェクトを文字列に変換することができます.
 
その他にも,long, unsigned long, double 型に変換する関数もあります.

GMPでの基本的なデータ型

GMPで扱う数値の型は基本的には次の3つです.
 
1) mpz_t : 多倍長整数
2) mpq_t : 多倍長有理数(分数表現)
3) mpf_t : 多倍長浮動小数点数
 
【mpz_t】
 桁の長い整数の計算を行う場合に用いる型です.計算機環境の記憶資源が許す限り大きな桁数の計算ができます.
 
【mpq_t】
 除算(割り算)を行う場合に精度を落とさずに計算を行うには有利数(分数)を用います.ただし有理数の値の乗算・除算を繰り返すと分母,分子ともに大きな数になっていくので,記憶資源の消費量と計算時間がともに大きくなっていきます.
 計算の有効桁数(精度)を限定すると記憶資源の消費量と計算時間を一定の程度に抑えることができるので,その場合は次の mpf_t の型で計算を行うのが良いです.
 
【mpf_t】
 有効桁数を指定して(長く指定することも可)精度を限って計算を行う場合に使用する型です.