任意桁の計算

BigInteger

Java言語の IntegerDouble型は表せる桁数が決まっています.Integerは 32ビット,Longでも64ビットであるため,それぞれ,$-2^{31}〜2^{31} - 1$,$-2^{63}〜2^{63} - 1$ までの値までしか扱えません.

Javaでは任意桁の計算が行える型が存在します. 任意桁の整数を表すBigIntegerと任意桁の実数を表すBigDecimalです. これらを扱ってみましょう.

BigInteger の初期化

任意桁の整数を表す型です. BigIntegerを利用するときは,import java.math.BigInteger;というimport 文が必要です. BigInteger型の実体を作成するときは,new BigInteger("表したい数")のように数値を文字列で指定してください. この型を扱うとき,通常の四則演算記号が使えない点に注意してください.

BigInteger value1 = new BigInteger("10");
BigInteger value2 = new BigInteger("20");
BigInteger value3 = value1.add(value2); // => OK
BigInteger value4 = value1 + value2;    // => コンパイルエラー.

Integer型,BigInteger型の相互変換

プログラム中でInteger型の値をBigIntegerとして扱いたい場合や,逆にBigInteger型の値をInteger型として扱いたい場合があります. 以下のプログラムのような操作により,相互変換が可能です.

Integer intValue = 10;
// Integer型からBigInteger型へ変換する.
BigInteger bigValue = BigInteger.valueOf(intValue);
// BigInteger型からInteger型へ変換する.
// もし,bigValue が大きすぎて 32ビットに収まらない場合は,下位32ビットのみが返される.
Integer intValue2 = bigValue.intValue();

BigInteger の四則演算

上記のように,足し算は addというメソッド呼び出しで実現します. 以下に対応を掲載します.どれも BigInteger型の変数b1b2を使って計算しているものとします.

なお,BigDecimalも基本的にはBigIntegerと同じです. メソッド呼び出しで演算を行い,実体を作成するときは,実数を表す文字列を渡せば良いです.

サンプルプログラム

先ほど示した計算方法を実際にプログラムに書いてみましょう. 2つのBigInteger型の変数を作成し,四則演算,あまり,符号逆転の操作を行い,結果を表示します.

import java.math.BigInteger;
public class BigOperator{
    void run(){
        BigInteger b1 = new BigInteger("10");  // BigInteger型の実体を作成する.
        BigInteger b2 = BigInteger.valueOf(3); // Integer型からBigInteger型へ変換する.

        BigInteger result1 = b1.add(b2);       // b1 + b2
        BigInteger result2 = b1.subtract(b2);  // b1 - b2
        BigInteger result3 = b1.multiply(b2);  // b1 * b2
        BigInteger result4 = b1.divide(b2);    // b1 / b2
        BigInteger result5 = b1.remainder(b2); // b1 % b2
        BigInteger result6 = b1.negate();      // -b1

        System.out.printf("%s + %s = %s%n", b1, b2, result1);  // <= 13
        System.out.printf("%s - %s = %s%n", b1, b2, result2);  // <= 7
        System.out.printf("%s * %s = %s%n", b1, b2, result3);  // <= 30
        System.out.printf("%s / %s = %s%n", b1, b2, result4);  // <= 3
        System.out.printf("%s %% %s = %s%n", b1, b2, result5); // <= 1
        System.out.printf("-%s = %s%n", b1, result6);          // <= -10

        if(b1.compareTo(b2) > 0){ // b1 > b2
            System.out.println("b1 の方が b2 より大きい.");
        }
    }
}

例題 階乗改

第1講 練習問題 3. 階乗 を改良し, 桁あふれを起こさないようにしましょう. 前回作成した階乗のプログラムは,13!を正確に計算できません. これを BigInteger を使って,どんな数値が与えられたとしても計算できるようにしてください. クラス名をBigFactorialとしてください. コマンドライン引数から値を受け取れるようにしましょう. また,コマンドライン引数で受け取る値はInteger型として扱って良いです.

出力例

$ java Factorial 12 # => 前回のプログラム.正しい結果の限界.
12! = 479001600
$ java Factorial 13 # => 前回のプログラム.正しくない結果.
13! = 1932053504
$ java BigFactorial 11
11! = 39916800
$ java BigFactorial 12 13 14 15
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
例題の解答例