2012-05-02 25 views
8

で異なるx = 31または32のJavaでは、次の2つの演算が異なる結果をもたらすのはなぜですか?x=3と同じ結果になりますか?Javaの結果は、(int)Math.pow(2、x)と1 << x

int x=3; 
int b = (int) Math.pow(2,x); 
int c = 1<<x; 

結果:

x=32: b=2147483647; c=1; 
x=31: b=2147483647; c=-2147483648; 
x=3: b=8   ; c=8 
+1

微妙な違いは、答えが同じでもpow()が**多く**遅くなることです。 pow()には丸め誤差がありますが、intはオーバーフローしています。 '1L << 32"は '2147483648'と同じです。 –

答えて

18

複数の問題は遊びであります

(int)Math.pow(2, x)1 << x0 ... 30範囲外xの値に対して等価でないことを示しています。

P.S. intの代わりにlong(および1の代わりに1L)の代わりにlongを使用すると、他の2つの結果とは異なる別の結果が得られることに注意することはおそらく興味深いでしょう。これは、最終結果がintに変換されても保持されます。

+2

特に最後のポイントは非常に重要です。 –

2

は、int型の限界を考えてみましょう。どれくらいの数の数字を保持できますか?

+0

左シフトと明示的な2の違いについて質問します。 –

+1

そして、それが符号付きの型であるという事実を' int'の限界に加えてください。 –

3

文書Math.powによれば、doubleとreturn doubleの両方の引数を促進します。明らかに返される結果がdoubleで、それをintにキャストすると最高32ビットしか得られず残りは切り捨てられるので、常に(int) Math.pow(2,x);という値が得られます。ビットシフトを行うと、常にintで処理されるため、オーバーフローが発生します。

+0

私は仮数の上位32ビットを推測しています。私は間違っているかもしれない。 – asenovm

+0

ええ、そうかもしれません。私はちょうど '2^31-1'を返すように思い出しました。コメントを削除しました:) –

0

intのサイズは32ビットで、デフォルトで署名されているため、最初のビットが符号として使用されます。左に31ビットシフトすると、Two's Complimentが得られます。これは - (2^32)です。 32ビット左にシフトすると、1に戻ります。intの代わりにlongを使ってこのシフトを実行すると、63 +ビットをシフトするまでの答えが得られます。

0

ここでは、長い場合のマイクロベンチマークがあります。私のラップトップ(2.8GHz)では、Math.powの代わりにシフトを使用すると、7倍以上速くなります。

int limit = 50_000_000; 
@Test 
public void testPower() { 
    Random r = new Random(7); 
    long t = System.currentTimeMillis(); 
    for (int i = 0; i < limit; i++) { 
     int p = r.nextInt(63); 
     long l = (long)Math.pow(2,p); 
    } 
    long t1 = System.currentTimeMillis(); 
    System.out.println((t1-t)/1000.0); // 3.758 s 
} 
@Test 
public void testShift() { 
    Random r = new Random(7); 
    long t = System.currentTimeMillis(); 
    for (int i = 0; i < limit; i++) { 
     int p = r.nextInt(63); 
     long l = 1L << p; 
    } 
    long t1 = System.currentTimeMillis(); 
    System.out.println((t1-t)/1000.0); // 0.523 s 
} 
関連する問題