第7章 Nashorn JavaScript エンジンの活用 : 問題 3 : BigInteger と Number
問題
jjs を実行して、次の呼び出しを行え
var big = new java.math.BigInteger('1234567890987654321')
- big の値を表示するとどうなるか?
- big の下3桁
big.mod(java.math.BigInteger('1000'))
は何か?
解答
jjs> var big = new java.math.BigInteger('1234567890987654321') jjs> big 1234567890987654400 jjs> big.mod(new java.math.BigInteger('1000')) 321
即ち、表示すると “有効桁数が足りなくて下3桁の値が変わっている” のに “内部的には指定した値を保持” している
さらに問題
なぜ奇妙な表示になるのか?
解答
big の内部形式はjava.math.BigInteger
だが
jjs> big.class class java.math.BigInteger
JavaScript でのデータ型は Number でプライマリデータ型である
jjs> typeof big
number
JavaScript の Number 型は倍精度の浮動小数なので、big を表示する際にメソッド
public double doubleValue()
を呼び出してマーシャリングされるため
BigInteger big = new BigInteger("1234567890987654321"); double number = big.doubleValue(); System.out.println(number);
1.2345678909876544E18
倍精度では有効桁数が足りず17桁目以降が化けてしまう
さらに問題
実際の値はどうすれば表示できるか?
解答
■ toString()
メソッド
最初に思いついたのはjava.math.BigInteger
クラスのtoString()
メソッドを呼ぶこと
jjs> big.toString() 1234567890987654400 jjs> big.toString(10) 1234567890987654400
残念、駄目だった
実は、JavaScript の Number インスタンスはtoString()
メソッドを持っている
つまりbig.toString()
は、JavaScript のメソッドが呼ばれているので、big はマーシャリングされて下3桁が欠けてしまう
■ Java.to()
でキャスト
Java.to()
メソッドを使ってjava.math.BigInteger
にキャストすれば、Java のtoString()
メソッドが呼べるのでは…
jjs> Java.to(big, java.math.BigInteger)
<shell>:1 TypeError: 1234567890987654400 is not an Object
これも駄目だった
■ 商と剰余に分ける
big
の場合だったら、以下のようにして商と剰余を求めればよい
jjs> var a = big.divide(new java.math.BigInteger('1000')) jjs> var b = big.mod(new java.math.BigInteger('1000')) jjs> a.toString() + b 1234567890987654321
どんな BigInteger でも正確な値を表示するには、次の関数を呼び出せばよい(これを1行で書くのは気が重いが…)
// BigInteger を文字列に変換 function bigToString(/* BigInteger */ num) { var result = ""; // 符号 if (num.signum() < 0) { result = "-"; num = num.negate(); } // 上位の桁から数字を求める for (var n = num.toString().length() - 1; n > 0; n--) { result += num.divide(java.math.BigInteger.TEN.pow(n)).toString(); num = num.mod(java.math.BigInteger.TEN.pow(n)); } result += num.toString(); return result; }