Double.parseDouble("2.2250738585072012e-308")
実際のソースを見て、解析してみました。
// 問題のコード Double.parseDouble("2.2250738585072012e-308");
これが問題のコードですが、Double.parseDouble()の中身は以下のようになっています。
import sun.misc.FloatingDecimal; public final class Double extends Number implements Comparable<Double> { ... public static double parseDouble(String s) throws NumberFormatException { return FloatingDecimal.readJavaFormatString(s).doubleValue(); } ... }
実際にはsun.misc.FloatingDecimal が呼ばれています。
今回問題となるのは、後者のdoubleValue()になります。
まず前者のreadJavaFormatString() は文字列を解析し、符号、指数部、仮数部、指数部、異常な値かどうかを判断しています。
このメソッドが返すのは、FloatingDecimalのオブジェクトであり、問題の文字列では、以下のコンストラクタの値と同じ物を返します。
new FloatingDecimal(false, -307, "22250738585072012******", 17, false)
個々の引数は以下の内容です。
マイナスか? false 指数部 -307 仮数部の文字列 "22250738585072012******" ここで'*'は初期化されたままの文字'\u0000' 仮数部の文字数 17 異常な値か? false
すなわち、0.22250738585072012e-307 という数値をあらわしています。
次の doubleValue()は上記のオブジェクトから、doubleの値に変換しています。
変換は大きく分けて2段階で行っています。
前半は、上記の値からおおよその数値を求めています。
後半は、より精度をあげるため、丸め幅(ulp:Units in the Last Place)の1/2になるまで、小さな値を足したり引いたりしています。
通常なら一度で誤差が1/2になり、ループから抜けます(多分)。
ところが、その判断の仕方が1ケタ間違っているため、無限にループを回っています。
問題の値では、以下のように足したり引いたりしながらいつまでも続きます。
2.2250738585072014E-308 2.225073858507201E-308 2.2250738585072014E-308 2.225073858507201E-308 2.2250738585072014E-308 2.225073858507201E-308 2.2250738585072014E-308 2.225073858507201E-308 ...
現象としては無限ループであり、CPU負荷があがり、処理が戻らなくなります。
そのプロセスが異常終了したり、メモリを食いつぶすことはないでしょう。
他のプロセスが誤動作することもないでしょう(CPU負荷を除けば)。
また、JavaVM上で動いているので、セキュリティ上の問題となることもないでしょう。
(保証はできませんが、ソースでの確認、および動作確認した感じではそうでした。)
コードを読んだ感じでは、他の値でも起こりうるのではないかと思います。
少なくとも、以下のパターンでも同様の現象が起こります。
パターン1:前後に空白文字がある場合。
最初にtrim()しているので、前後に空白文字がある場合でも同様の現象が起きます。
例 " 2.2250738585072012e-308"
パターン2:指数部の文字がE/eの大文字小文字が異なる場合。
例 "2.2250738585072012E-308"
パターン3:末尾にD,d,F,fがある場合。
末尾にD,d,F,fがあっても読み飛ばしているだけなので、同様の現象が起きます。
例 "2.2250738585072012e-308D"
パターン4:符号が異なる場合。ついている場合。
例 "-2.2250738585072012e-308"
例 "+2.2250738585072012e-308"
パターン5:仮数部と指数部が異なっても同じ数値を表すとき。
例 "0.22250738585072012e-307"
例 "22.250738585072012e-309"
パターン6:仮数部に有効桁数以上の数値がある場合
例 "2.225073858507201200000000e-308"
例 "2.225073858507201244444444e-308"
(2011/03/02追記)KINさんのコメントにあるように、数字が続く場合なら常に起こるわけではなく、2進数にしたとき有効桁数に影響を及ぼさない程度の端数があるときです。
他にも同じ現象を起こすパターンがあるかもしれません。