私は次の機能を持っています
int sign(int x) {
int sign = (x >> 31);
sign = sign | 1;
return sign;
}
以下を希望します。
- 負の数の場合は -1 を返します (最初の行)
- 正数の場合は 1 を返します (2 行目)
- ゼロの場合は 0 を返す
この最後の項目に行き詰まっています。x がゼロの場合、ビット単位の演算子のみを使用してゼロを返すにはどうすればよいですか?
私は次の機能を持っています
int sign(int x) {
int sign = (x >> 31);
sign = sign | 1;
return sign;
}
以下を希望します。
この最後の項目に行き詰まっています。x がゼロの場合、ビット単位の演算子のみを使用してゼロを返すにはどうすればよいですか?
素敵な小さなパズル。32 ビット整数があるとします。
int sign( int x )
{
// if any bit is on, all bits are on. else zero.
int lowBit = x;
lowBit |= lowBit >> 16;
lowBit |= lowBit >> 8;
lowBit |= lowBit >> 4;
lowBit |= lowBit >> 2;
lowBit |= lowBit >> 1;
lowBit &= 1;
int signBit = x & 0x80000000;
signBit |= signBit >> 16;
signBit |= signBit >> 8;
signBit |= signBit >> 4;
signBit |= signBit >> 2;
signBit |= signBit >> 1;
signBit &= 0xFFFFFFFE;
return signBit | lowBit;
}
これがどのように機能するかです。4ビットの数字で説明しますが、説明は一般化します。ビット パターンの 3 つのカテゴリからマッピングを作成する必要があります。
0000 -> 0000
0xxx -> 0001
1yyy -> 1111
ここで、x は 000 以外の任意の値、yyy は任意の値です。
したがって、最初に、レジスタ内のいずれかのビットが 1 の場合は 1 であり、それ以外の場合は 0 であるビットが必要です。そのため、いずれかのビットがハイの場合はすべてのビットがハイになるようにレジスタを「スミア」し、そのビットを結果のロー ビットの値として保持します。
次に、符号ビットを「塗りつぶします」。最後に、それらを一緒に「or」します。
読者のための演習: 32 ビットの int があるが、64 ビットのレジスタがある場合、操作の数を半分に削減できます。
更新: 常に改善できます (未テスト):
int sign( int x )
{
int lowBit = !!x; // double ! operator, wtf? yes...
int signBit = x & 0x80000000;
signBit |= signBit >> 16;
signBit |= signBit >> 8;
signBit |= signBit >> 4;
signBit |= signBit >> 2;
signBit |= signBit >> 1;
signBit &= 0xFFFFFFFE;
return signBit | lowBit;
}
これを使って
int sign(int x) {
int sign = (x >> 31);
sign = sign | (~(1<<((x|(x>>5)|(x>>10)|(x>>15)|(x>>20)|(x>>25)|(x>>30))&0x1F))&0x1);
return sign;
}
アイデアは、カウントで左シフト1
することです。x
したがってx==0
、最初のビットが保持される場合1
その場合x!=0
、最初のビットは次のように変更されます0
そして、sign = sign | (~(First bit))
それは同等です
sign = sign | (~(1<<x) & 0x1);
1
ただし、シフトをx
で左に移動する場合は注意が必要です。これx
は、型フォーマットのサイズ (32) に対して >= になる可能性があり、x
が負になる可能性があり、どちらの場合も未定義の動作になるためです。
上記の問題を回避するために、32 ビット ( x
) を 7 つのブロックに分割し、各ブロックには 5 ビットが含まれますが、最後のブロックには 2 ビットが含まれます|
。
y=(bloc1|bloc2|bloc3|bloc4|bloc5|bloc6|bloc7)
もしそうx!= 0
ならy!=0
もしそうx==0
ならy==0
y
( )の最初の 5 ビットのみを取得する必要があります&0x1F
。ここで、それは否定的でy
はなく、y<32
そして、でシフトする代わりに、でシフトして、未定義の動作を回避x
できますy
これも使えます。それは私の前の答えと同じ論理を持っています
int sign(int x) {
int y = x;
y |= y >> 16;
y |= y >> 8;
y |= y >> 4;
y &= 0xF;
int sign = (x >> 31);
sign = sign | (~(1<<y) & 0x1);
return sign;
}