Math::BigInt
任意長整数を扱うモジュール。演算自身は別のモジュールに実装されている基本的な演算(四則演算、論理演算など)を組み合わせて高度な関数演算を提供している。基本演算を実行するモジュールは、いくつかあって選択できる。
use Math::BigInt try => 'GMP, Pari, FastCalc, Calc';
パッケージをロードして、Math::BigInt::GMP → Math::BigInt::Pari → Math::BigInt::FastCalc
→ Math::BigInt::Calc の順に演算モジュールを探してインポートする。
try => ではなく、lib => を使うほうが一般的であるが、lib
だとモジュールが見つからなかった時にワーニングが出力される。ちなみに、only => だと、モジュールが見つからないとエラーになる。
演算モジュールは、どれか1つインストールしてあればよい。何もインストールしていないと、Math::BigInt の標準演算モジュールの
Math::BigInt::Calc が使われるが、このモジュールはとても遅い。
実測した感じでは、"速い > GMP > Pari >> FastCalc > Calc > 遅い"。FastCalc
と Calcの差は、ほとんど誤差レベルである。特に制約がなければ、GMP を使えばよい。
ほとんどのメソッドは、オブジェクトに演算を実行してオブジェクトを書き換えるように作られている。格好よく言えば、OOP (Object
Oriented Programming)
が出来るように作られているのだが、不用意に普通の関数風に呼び出すと、オブジェクトが書き換わってしまうので注意が必要。
例えば、$c = $a * $b; を実行する時に、$c = $a->bmul($b); と書くと、掛け算の結果が $c と $a
の両方に代入されてしまう。正しくは、$c = $a->copy()->bmul($b); である。
newした時の初期値
・ 引数が不正の時は、NaNに初期化される。コンストラクターがundefを返すことはない。
・
引数がundefの時は、0に初期化される。
・ 引数がリスト参照やハッシュ参照の時は、エラーが発生する。
・
引数がMath::BigIntオブジェクトの時は、copy( ) が実行される。
スカラー値との演算に関する注意:
スカラー値とBigIntオブジェクトの演算結果は、BigIntオブジェクトになる。
例えば、
$x->copy()->blog(2) + 1
を実行すると、BigIntオブジェクトで$xのビット数が得られる。
もし、演算結果をスカラー値にしたいのであれば、下記の様にする。
$x->copy()->blog(2)->numify() + 1
# Number creation my $x = Math::BigInt->new($str); # defaults to 0 $h = Math::BigInt->new('0x123'); # from hexadecimal $b = Math::BigInt->new('0b101'); # from binary $o = Math::BigInt->from_oct('0101'); # from octal $o = Math::BigInt->from_hex('abcd'); # from hexadecimal, 先頭に 0x があってもOK my $y = $x->copy(); # make a true copy my $nan = Math::BigInt->bnan(); # create a NotANumber my $zero = Math::BigInt->bzero(); # create a +0 my $inf = Math::BigInt->binf(); # create a +inf my $inf = Math::BigInt->binf('-'); # create a -inf my $one = Math::BigInt->bone(); # create a +1 my $mone = Math::BigInt->bone('-'); # create a -1 $x->is_zero(); # if $x is +0 $x->is_nan(); # if $x is NaN $x->is_one(); # if $x is +1 $x->is_one('-'); # if $x is -1 $x->is_odd(); # if $x is odd $x->is_even(); # if $x is even $x->is_pos(); # if $x > 0 $x->is_neg(); # if $x < 0 $x->is_inf($sign); # if $x is +inf, or -inf (sign is default '+') # comparing and digit/sign extraction $x->bcmp($y); # compare numbers (undef,<0,=0,>0) $x->bacmp($y); # compare absolutely (undef,<0,=0,>0) $x->sign(); # return the sign, either +,- or NaN $x->digit($n); # return the nth digit, counting from right $x->digit(-$n); # return the nth digit, counting from left $x->bzero(); # set $x to 0 $x->bnan(); # set $x to NaN $x->bone(); # set $x to +1 $x->bone('-'); # set $x to -1 $x->binf(); # set $x to inf $x->binf('-'); # set $x to -inf $x->bneg(); # negation $x->babs(); # absolute value $x->bsgn(); # sign function (-1, 0, 1, or NaN) $x->bnorm(); # normalize (no-op in BigInt) $x->bnot(); # two's complement (bit wise not) $x->binc(); # increment $x by 1 $x->bdec(); # decrement $x by 1 $x->badd($y); # addition (add $y to $x) $x->bsub($y); # subtraction (subtract $y from $x) $x->bmul($y); # multiplication (multiply $x by $y) $x->bdiv($y); # divide, set $x to quotient return (quo,rem) $x->bmuladd($y,$z); # $x = $x * $y + $z $x->bmod($y); # modulus (x % y) $x->bmodpow($y,$mod); # modular exponentiation (($x ** $y) % $mod) $x->bmodinv($mod); # modular multiplicative inverse $x->bpow($y); # power of arguments (x ** y) $x->blsft($y); # left shift in base 2 $x->brsft($y); # right shift in base 2 returns (quo,rem) $x->blsft($y,$n); # left shift by $y places in base $n $x->brsft($y,$n); # right shift by $y places in base $n returns (quo,rem) $x->band($y); # bitwise and $x->bior($y); # bitwise inclusive or $x->bxor($y); # bitwise exclusive or $x->bnot(); # bitwise not (two's complement) # 平方根や三乗根が整数にならない場合でもエラーにならないので要注意 $x->bsqrt(); # calculate square-root $x->broot($y); # $y'th root of $x (e.g. $y == 3 => cubic root) $x->bfac(); # factorial of $x (1*2*3*4*..$x) $x->bnok($y); # x over y (binomial coefficient n over k) $x->blog(); # logarithm of $x to base e (Euler's number) $x->blog($base); # logarithm of $x to base $base (f.i. 2) $x->bexp(); # calculate e ** $x where e is Euler's number $x->round($A,$P,$mode); # round to accuracy or precision using mode $mode $x->bround($n); # accuracy: preserve $n digits $x->bfround($n); # $n > 0: round $nth digits, # $n < 0: round to the $nth digit after the dot # 割り算した時に整数になってしまうので使えない。Math::BigFloatが必要 $x->bfloor(); # round towards minus infinity $x->bceil(); # round towards plus infinity $x->bint(); # round towards zero # greatest common divisor (no OO style) my $gcd = Math::BigInt::bgcd(@values); # lowest common multiple (no OO style) my $lcm = Math::BigInt::blcm(@values); x->length(); # return number of digits in number $x->exponent(); # return exponent as BigInt $x->mantissa(); # return (signed) mantissa as BigInt $x->parts(); # return (mantissa,exponent) as BigInt $x->copy(); # make a true copy of $x (unlike $y = $x;) $x->as_int(); # return as BigInt (in BigInt: same as copy()) $x->numify(); # return as scalar (might overflow!) # conversion to string (do not modify their argument) $x->bstr(); # normalized string (e.g. '3') "$x" でも同じ結果が得られる。 $x->bsstr(); # norm. string in scientific notation (e.g. '3E0') $x->as_hex(); # as signed hexadecimal string with prefixed 0x $x->as_bin(); # as signed binary string with prefixed 0b $x->as_oct(); # as signed octal string with prefixed 0
補足事項
Math::BigInt::Pari の bmodpow (べき剰余)にはバグがある。0 のべき剰余は、べき乗数やモジュラスの値に関わらず常に
0 であるが、lib => 'Pari' で bmodpow を実行すると、常に 1 を返す。
---- bug.pl ---
print "use Math::BigInt lib => 'Calc'\n";
require "bug1.pl";
print "\n";
print "use Math::BigInt lib => 'Pari'\n";
require "bug2.pl";
---- bug1.pl ----
use Math::BigInt;
my $a = Math::BigInt->bzero();
my $b = Math::BigInt->new("12345678901234567890");
my $n = Math::BigInt->new("65537");
my $c = $a->copy()->bmodpow($b,$n);
print "$a->modpow($b,$n)=$c\n";
---- bug2.pl ----
use Math::BigInt (lib => 'Pari');
my $a = Math::BigInt->bzero();
my $b = Math::BigInt->new("12345678901234567890");
my $n = Math::BigInt->new("65537");
my $c = $a->copy()->bmodpow($b,$n);
print "$a->modpow($b,$n)=$c\n";
----- 実行結果 ----
use Math::BigInt lib => 'Calc'
0->modpow(12345678901234567890,65537)=0
use Math::BigInt lib => 'Pari'
0->modpow(12345678901234567890,65537)=1
これは、Pari のバグではなく、Math::BigInt::Pari のバグなので、perl モジュールの修正だけで直る。
CPANにバグレポートしておいたので、そのうち直るかも?