2015-11-16 6 views
6

Long.numberOfLeadingZeros(long i)の方法を見つける前に、私はlongをdoubleにキャストし、Math.getExponent(double d)を使用していました。考え方は、longの二重表現を見つけ、指数を使って最高のセットビットを得、それを64から引いて先行ゼロの数を得ることでした。出力の重要な部分とJava - 長い二倍の変換で先行ゼロを見つける

for (int i = 0; i < 64; i++) { 
    double max = Long.MAX_VALUE >>> i; 
    double min = Long.MIN_VALUE >>> i; 
    double neg = -1L >>> i; 
    System.out.format("Max: %-5d Min: %-5d -1: %-5d%n", Math.getExponent(dmax), 
           Math.getExponent(dmin), Math.getExponent(dneg)); 
} 

... 
Max: 55 Min: 55 -1: 56 
Max: 54 Min: 54 -1: 55 
Max: 52 Min: 53 -1: 54 
Max: 51 Min: 52 -1: 52 
Max: 50 Min: 51 -1: 51 
... 

憧れる

この

は、ほとんどの問題を強調するために使用されたforループ、以下の1でオフ時折働いたが、でしたすべてのビットが2^52より上に1だけオフになっています。 As this post explains, 52ビットの仮数部に53+の有効ビットを格納するために精度が低下します。しかし、私は指数が影響を受ける理由を理解するのに苦労しています。

私はもはやこのメソッドを使用していませんが、私はまだ不思議です:なぜ、どのような状況で、長い間に先行ゼロを見つけるこの方法は失敗しますか?

答えて

3

doubleに精度の制限がdouble値の浮動小数点表現の指数をインクリメント2の最も近いパワーに切り上げするバイナリ表現を強制します。これは、暗黙の1ビットを含む倍精度浮動小数点型の仮数が53ビットであるが、longのビット数が64ビットであるために発生します。 - ことを倍増するフロート、または長いから浮いて、または長いからするint型から拡大プリミティブ変換

、精度の損失をもたらす可能性があります

Section 5.1.2 of the JLSは、この拡大原始的な変換に何が起こるかカバーその結果、値の最下位ビットの一部が失われる可能性があります。この場合、結果の浮動小数点値は、IEEE 754ラウンド・トゥ・ビフォア・モード(§4.2.4)を使用して、整数値の正確に丸められたバージョンになります。

(強調鉱山)ここ

、Iは、元double Sの進値を出力するlongdoubleのビットを保存するDouble.doubleToLongBitsを使用し、Long.toHexString

System.out.format("Max(%s): %-5d Min(%s): %-5d -1(%s): %-5d%n", 
       Long.toHexString(Double.doubleToLongBits(dmax)), Math.getExponent(dmax), 
       Long.toHexString(Double.doubleToLongBits(dmax)), Math.getExponent(dmin), 
       Long.toHexString(Double.doubleToLongBits(dneg)), Math.getExponent(dneg)); 

出力:doubleに変換するとき

Max(43e0000000000000): 63 Min(43e0000000000000): 63 -1(bff0000000000000): 0  
Max(43d0000000000000): 62 Min(43d0000000000000): 62 -1(43e0000000000000): 63 
Max(43c0000000000000): 61 Min(43c0000000000000): 61 -1(43d0000000000000): 62 
Max(43b0000000000000): 60 Min(43b0000000000000): 60 -1(43c0000000000000): 61 
Max(43a0000000000000): 59 Min(43a0000000000000): 59 -1(43b0000000000000): 60 
Max(4390000000000000): 58 Min(4390000000000000): 58 -1(43a0000000000000): 59 
Max(4380000000000000): 57 Min(4380000000000000): 57 -1(4390000000000000): 58 
Max(4370000000000000): 56 Min(4370000000000000): 56 -1(4380000000000000): 57 
Max(4360000000000000): 55 Min(4360000000000000): 55 -1(4370000000000000): 56 
Max(4350000000000000): 54 Min(4350000000000000): 54 -1(4360000000000000): 55 
Max(433fffffffffffff): 52 Min(433fffffffffffff): 53 -1(4350000000000000): 54 
Max(432ffffffffffffe): 51 Min(432ffffffffffffe): 52 -1(433fffffffffffff): 52 

以上53個の1ビットを有する元long値は精度を失う、切り上げれます。指数フィールドは、2から12のビットで構成され、上に出力された最初の3桁の16進数で表示されます。値は53 1ビット下方にシフトされる場合

doubleの精度は、現在の丸めなしでの値を保持するのに十分である(ラウンドアップはもはや必要である)と仮数のビットとして見えるようになる 『F』進数字。指数部のフィールドには、435から433に不連続があり、Math.getExponentの結果に不連続がある理由を説明します。54から52までです。

+0

これは理にかなっています。投稿を読んだ後、私は2^53 - 1より大きい値を11の最下位ビットを '0xFFFFFFFFFFFFF700L;'で降下させました。ダブルに変換する前に、丸めを不要にします。私はまた、仮数に余分な暗黙のビットがあることを忘れてしまった。詳細な答えをありがとう! –

1

数字がすべて1で、より少ない場所に丸められたときに切り上げられ、1ビット長くなります。例えば、(仮数部には5ビットしかないと仮定します)

111111 becomes 1000000 

関連する問題