2.2250738585072012e-308
をdoubleに変換するときに無限ループに入ります。 理論的には、数値は
0x1p-1022
、つまり
0x1p-1022
に変換する必要があります。 ただし、Javaはdoubleの最大の非正規化数である
0x0.fffffffffffffp-1022
でフリーズします。
実行時の無限ループ
class RuntimeHang { public static void main(String[] args) { System.out.println("Test:"); double d = Double.parseDouble("2.2250738585072012e-308"); System.out.println("Value: " + d); } }
コンパイル時の無限ループ
( Eclipseで試してみたい場合は、最初にすべてを保存することを忘れないでください。そうしないと、シャドウコンピレーションで感覚をつかむことができません 。
class CompilationHang { public static void main(String[] args) { double d = 2.2250738585072012e-308; System.out.println("Value: " + d); } }
猫の下で、この現象の原因に関する著者の推論。
問題は何ですか?
Konstantinは、少なくとも実行時には、問題はFloatingDecimal.javaの 「修正サイクル」にあることを発見しました。 彼はこう書いている:
この部分をコメントアウトすると、sun.misc.FloatingDecimal.readJavaFormatString(s).doubleValue()
を呼び出すsun.misc.FloatingDecimal.readJavaFormatString(s).doubleValue()
Double.parseDouble(String s)
は純粋なJavaコードであり、ネイティブではないため、Double.parseDouble(String s)
にハングアップはありません。 ただし、浮動小数点演算を使用するため、JREとjavacがコンパイルされたコンパイラ設定になる可能性があります。
修正サイクルがない場合、そのようなビット(ビッグエンディアン)が出力されます。
00000000 00001111 11111111 11111111 11111111 11111111 11111111 11111111
つまり、指数はゼロであるため、数値は最大の非正規化浮動小数点数に変換されます。 修正サイクルがないと、2.2250738585072013e-308
同じことが起こりますが、サイクルのコメントを2.2250738585072013e-308
、正しく変換されます:
00000000 00010000 00000000 00000000 00000000 00000000 00000000 00000000
翻訳者から
32ビットおよび64ビットのHotSpotおよび64ビットのOpenJDKで問題を確認して再現しました。 さらに、 PHPにも同様の問題があります 。 Konstantin Preisserはすでにバグレポートを送信しています。