15

モノクロ ビットマップからビットを読み取っています。16 ビットごとshortに逆の順序で格納しています。ビットマップのビットが黒の場合は 1 を格納します。白の場合は 0 を格納します。

例: ビットマップの場合: bbbw bbbw bbbw wwww
my short is: 0000 0111 0111 0111

私がこれをやろうとした最初の方法は次のとおりです。

short m;
// ...
Color c = bmp.GetPixel(j, i);
if (c.R == Color.Black)
    m |= short.MinValue;
m >>= 1;
// ...

1 つの割り当てとシフトの後、予想される -32768 (1000 0000 0000 0000) を取得しました。
2回目で-16384(1100 0000 0000 0000)になりました。

使用するコードをushort変更し、if行をに変更したs |= (ushort)Math.Pow(2, 15);ところ、動作するようになりました。

私の質問は、.NET で符号ビットがシフトしないのはなぜですか? 符号ビットをシフトする方法はありますか?

4

5 に答える 5

36

C# では、シフトは(論理シフトとは対照的に)算術シフトです。右算術シフトでは、符号ビットが左にシフトされるため、数値の符号は保持されます。右シフトは 2 で除算することと同じです。

代替テキスト

論理シフト (符号拡張なし)が必要な場合は、符号なしの数値を使用します

代替テキスト

于 2009-09-30T17:55:08.933 に答える
5

http://msdn.microsoft.com/en-us/library/k2ay192e.aspx

「>> 演算子は、expression2 で指定されたビット数だけ、expression1 のビットを右にシフトします。expression1 の符号ビットは、左から数字を埋めるために使用されます。右にシフトされた数字は破棄されます。expression1 のデータ型によって決定されます。この演算子によって返されるデータ型。」

于 2009-09-30T17:54:52.933 に答える
3

C# で符号付き整数を右シフトすると、左側のビットが符号ビットで埋められます。事実上、符号付き整数を 1 ビット右シフトした結果は、それを 2 で除算することと同じです。

この種の右シフトは他の場所でも見られます。たとえば、x86 アセンブリでは、 sar(左側のビットを符号ビットで埋める)命令と (shr左側のビットをゼロで埋める) という 2 つの異なる命令が提供されます。

C# でこの動作が望ましくない場合は、シフト時に符号なしの型を使用する必要があります。

于 2009-09-30T17:50:00.120 に答える
2

http://www.blackwasp.co.uk/CSharpShiftOperators.aspxごと

...符号付き整数は、変数の値が正か負かを判断するために最上位ビットを使用し、残りのビットは負の値に2の補数表記を使用することを決定します。最上位ビットは通常、左シフトのオーバーフロービットと見なされます。手術。これを可能にするために、C#は、このビットを符号付きデータ型に合わせて調整してはならず、それに応じて負の数をシフトする必要があることを理解しています。したがって、シフトは正の値だけでなく負の値でも機能します。

int value = -240;
int halved = value >> 1;      // Result = -120
于 2009-09-30T17:57:50.503 に答える
1

あなたが知っているように、あなたの質問に対する簡単な答えは、符号ビットを持ち込まないように符号なし整数を使用することです。それで問題ありません。ただし、次のことを考慮してください

最適化のヒント

このような変換を多数行う必要があると仮定すると (通常、ビットマップには多数のピクセルが存在します)、ビット パターンの逆バージョン (または変換が可能なものは何でも) を直接提供する 256 バイトの配列を使用することを検討する必要があります。 be) 1 つの完全なバイト。次に、16 ビット ワードの上位バイト値または下位バイト値のいずれかを使用して、この配列に直接インデックスを付けると、8 ビットすべての結果が得られます。時間/パフォーマンスが重視される場合 (およびスペースが利用可能である場合) は、64k の配列サイズを使用して、一度に 1 つの完全なワードを処理することもできます。

あなたの例で指定された変換を考えると、事前に計算された値の配列は次のようになります。

    byte[] mirror = { 
       0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
       0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
       0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x78, 0xF8,
       // etc..
       0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
    };
于 2009-09-30T17:52:51.790 に答える