11

Java の場合:

(0xFFFFFFFF <<  1) = 0xFFFFFFFE = 0b1111111111111110
                :         :               :
(0xFFFFFFFF << 30) = 0xE0000000 = 0b1110000000000000
(0xFFFFFFFF << 30) = 0xC0000000 = 0b1100000000000000
(0xFFFFFFFF << 31) = 0x80000000 = 0b1000000000000000

でも:

(0xFFFFFFFF << 32) = 0xFFFFFFFF = 0b1111111111111111

論理的にはこれは意味がありませんが、Java が次のような操作を実行していると私は信じています。

a << (b % Integer.SIZE)[編集、どうやら:]a << (b & 0x1F)

>>これはとにも当てはまり>>>ます。

明らかに >= 32 (整数の場合) だけシフトすると、データ型からすべてのデータが削除されますが、これが役立つ場合もあります。例えば:

int value = 0x3F43F466; // any value
int shift = 17; // any value >= 0
int carry = value & (-1 << (Integer.SIZE - shift));
if (carry > 0)
    ; // code...

もちろん、これは修正できますが、これらのバグを見つけるにはかなりの時間がかかります (同様のバグを追跡するのに何時間も費やしました)。それで、私の質問:すべてのビットをシフトアウトするときに論理値を返さない理由はありますか?

アップデート:

以下を使用して、C99でこれを試しました:

#include<stdio.h>
main()
{
   int i, val;
   for (i = 0; i <=36; i++) {
       val = (-1 << i);
       printf("%d :\t%d\n", i, val);
   }
}

Java と同じように動作し、 masking であることがわかりましたがi & 0x1F、定数値を指定するとコンパイル時に警告が表示されます。

warning: left shift count >= width of type
4

2 に答える 2

8

確かに、それはほとんどのプロセッサ (特に x86 を含む) がビットシフトを実装する方法であり、必要なことを実行する方法です。シフトが 32 より大きいかどうかを確認し、そうであればゼロを返します。最新の CPU では高価です。それは単に「煩わしい」だけでなく、物事を桁違いに遅くする可能性があります。

要するに、やりたいことを実行すると、高性能コードによって非常に高速であると予想される操作にかなりのオーバーヘッドが追加されます。

参考までに、ロジックは とまったく同じではなく%、マスクです。詳細については、 JLS 15.19を参照してください。

左側のオペランドの昇格された型が int の場合、右側のオペランドの下位 5 ビットのみがシフト距離として使用されます。これは、右側のオペランドがマスク値 0x1f (0b11111) を使用してビットごとの論理 AND 演算子 & (§15.22.1) にかけられたかのようです。したがって、実際に使用されるシフト距離は、常に 0 から 31 までの範囲になります。

于 2013-03-29T18:06:30.397 に答える
4

JLS 15.19 拡張 された左側のオペランドの型が int の場合、右側のオペランドの下位 5 ビットのみがシフト距離として使用されます。これは、右側のオペランドがマスク値 0x1f (0b11111) を使用してビットごとの論理 AND 演算子 & (§15.22.1) にかけられたかのようです。したがって、実際に使用されるシフト距離は、常に 0 から 31 の範囲になります。

簡単に言えば、 0xFFFFFFFF << 32同等to 0xFFFFFFFF << (32 & 0x1f)であると同等です0xFFFFFFFF << 0

于 2013-03-29T18:09:05.920 に答える