0

クライアント/サーバー、Web、デスクトップ開発などの現代のコンテキストでビットシフトを利用するために、人々がどのような使用パターンを確立したか知りたいです。デバイス ドライバ以外のソフトウェア開発におけるビット シフトの使用法は何ですか?

どのビット演算/シフト手法を使用する必要がありますか? 再利用できるアルゴリズムにはどのようなものがありますか?

4

8 に答える 8

3

非常に大きな配列の中点を見つけるときに、基本的にすべての既存のライブラリ バイナリ検索でオーバーフロー エラーが発生することが最近発見されました。Java で実装されているこの修正では、除算の代わりに右シフトを使用します。この記事を参照してください。

于 2009-10-20T13:15:54.097 に答える
3

それは本当に言語、開発中のアプリケーションなどに依存します。そうは言っても、私はHacker's Delightを見ます。お探しのものがあると思います。

于 2009-10-20T13:08:09.237 に答える
2

ビットシフト操作を行う理由は 3 つあります。

1 つは、整数の乗算と除算を行う別の方法です。左に 1 桁シフトすることは、2 を掛けることと同じです。1 桁を右にシフトすることは、2 で除算することと同じです。パフォーマンスをわずかに改善するために、コードを読みにくく理解しにくくするため、私はめったにこれを行いません。一部のコンパイラは、定数で乗算または除算する場合にこれを行うのに十分なほどスマートです。この場合、ゲインはゼロです。最近この手法を使用するのは、非常に計算量の多いものに限られます。log や sin の評価など、無限級数の多くの項を大量に評価する数学ライブラリを書いていたら、おそらくこのようなものを使用するでしょう。そうでなければ、私の謙虚な意見では、次のプログラマーを混乱させるという代償を払う価値はありません。

2 つ目は、複数の論理フィールドを 1 つのフィールドにパックする方法として、AND および OR と組み合わせて使用​​することです。可能な値の範囲が 0 ~ 3 のフィールドと、0 ~ 7 のフィールドがあるとします。1 つ目は 2 ビット、2 つ目は 3 ビットに収まる可能性があります。したがって、両方を 1 バイトにパックできます。次のようなコードでそれらを入れることができます:

byte b=(f1<<3) | f2;

あなたはそれらを得ることができます:

f2=b & 0x07;
f1=(b>>3) & 0x03;

6kB の RAM を搭載したコンピューターで作業していた古き良き時代には、必要なすべてのデータをメモリに詰め込むために、この種のことを何度も行いました。今日、デスクトップに 1 ギガバイト、サーバーに数ギガバイトを使用している場合、これを行うことの複雑さが増し、「間違いを犯す場所が増える」と読むと、それだけの価値はありません。携帯電話やその他の非常にメモリに制約のある環境向けの組み込みコードを作成している場合でも、このようなことを行う必要があるかもしれません。本当に膨大な量のデータがメモリに必要なプロジェクトに取り組んでいる場合、つまりヒトゲノムなどを分析している場合、これが必要になる可能性があります。しかし、ほとんどの場合、これを行う方法を知ることは、計算尺の使い方を知るようなものです。今日ではほとんど実用的価値のない興味深い歴史的遺物です。

3 つ目は、ディスクからの読み取りまたはディスクへの書き込み時のデータ型間の変換、または異なるデータ ストレージ形式を持つ別のシステムとの通信です。たとえば、4 バイトの 2 進数をディスクに書き込むとします。このファイルを読み取る一部のコンピューターは整数を最初に最上位バイトで格納し、他のコンピューターは最下位バイトを最初に格納します。両方がデータを正しく読み取れるようにするには、一貫した方法でデータを保存および取得する必要があります。したがって、1 つのバイト順を選択し、その方法で格納するように強制します。お気に入り:

for (int p=0;p<4;++p)
{
  byte b=i & 0xff;
  out.write(b);
  i=i>>8;
}

最近、ビットシフトを使用するのはこれだけです。

于 2009-10-20T13:43:45.350 に答える
2

最近のビット操作の主な用途は、フラグ ワードです。(それとも私だけでしょうか? :-) これにより、1 つの整数変数を使用して、多数のブール値をコンパクトかつ効率的な方法で格納できます。これには、シフトを使用せず、AND および OR 演算のみを使用して、異なるビット値をテストおよび設定します。これは多くの場合、コードをより効率的にするために使用できます (パラメーターとして 32 個の bool の配列の代わりに 1 つの 32 ビット整数を渡します。単一のビット演算で任意のフラグのグループを設定/クリア/トグル/テストするなど)。

もう 1 つの一般的な用途は、データをよりコンパクトな形式に圧縮することです (通信、ファイル形式、およびメモリが不足している組み込みコントローラーなどのアプリケーションで一般的です)。たとえば、0 ~ 25 の範囲の数値がある場合、byte (8 ビット) または int (多くの場合、 32 ビット以上)。

一部のアーキテクチャ/コンパイラでは、乗算/除算演算をビットシフトと加算の組み合わせに置き換えることで演算を高速化できますが、最新のコンパイラのほとんどは、そうする機会を見つけた場合にこれを実行します。たとえば、最適化コンパイラを使用している場合、「a *= 2」は「a <<= 1」に変換される可能性があります。

次に、時々便利な斬新な使用法がいくつかあります (別の回答で既に述べたように、Hackers Delight を参照してください)。

Windows フォームまたは Web タイプのアプリケーションを実行しているだけの場合、ビット単位の操作を使用する大きな必要性はない可能性がありますが、これらの高レベルの環境でも、場合によってはビット単位の操作を使用して物事をよりクリーンにすることができます。より効率的です。または、少なくとも配管工のように少し感じず、職人のように感じてください :-)

于 2009-10-20T13:40:47.313 に答える
1

これは、ピクセルのバッファを操作するために使用したビットシフトとマスキングの優れたアプリケーションです。

bool pBuffer::GetPixel(unsigned int x, unsigned int y)

{{

char c = blocks[((y * width) + x) / 8];

return (bool)((c >> (((y * width) + x) % 8) & 1));

}

幅と高さは、おそらく2次元配列の既知の次元です。ただし、配列(blocks [])は1次元のみです。charの各ビットは、オンまたはオフのピクセルを表します。

この機能は、ユーザーが最小限のメモリを使用して画面に2Dレベルをペイントできるようにするために、凸包アルゴリズムの実装で使用されました。

重要なのは、ビットがデータをどのように表現しているかを知っている場合、ビットシフトによってそのデータに対して卑劣なことを行うことができるということです。

于 2009-10-20T13:49:25.463 に答える
1

The Art of Computer Programming、Vol。IV、Fasc。1はあなたの路地のすぐ上になります。

于 2009-10-20T13:53:51.233 に答える
1

They can be very useful with bit mask enumerations e.g.

  enum flags {
    IMAGE_FLIP_HORIZONTAL   =1 << 0,
    IMAGE_FLIP_VERTICAL     =1 << 1,
    IMAGE_DESATURATE        =1 << 2,
    IMAGE_INVERT            =1 << 3,
    IMAGE_NOALPHA           =1 << 4 
  };

Then you may provide an API which allows

loadImage("pirate.gif", IMAGE_DESATURATE | IMAGE_FLIP_HORIZONTAL);

If you ever use libpng there is a chance you are using this type of enum. In pngread.c there is a block at the end of the file which uses masks like this to apply transformations:

#if defined(PNG_READ_INVERT_SUPPORTED)
   /* invert monochrome files to have 0 as white and 1 as black
    */
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
       png_set_invert_mono(png_ptr);
#endif

#if defined(PNG_READ_BGR_SUPPORTED)
   /* flip the RGB pixels to BGR (or RGBA to BGRA)
    */
   if (transforms & PNG_TRANSFORM_BGR)
       png_set_bgr(png_ptr);
#endif

#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
   /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR)
    */
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
       png_set_swap_alpha(png_ptr);
#endif

#if defined(PNG_READ_SWAP_SUPPORTED)
   /* swap bytes of 16 bit files to least significant byte first
    */
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
       png_set_swap(png_ptr);
#endif
于 2009-10-20T14:21:41.803 に答える
0

「現代」の観点から、ビットシフト?いいえ... Cを使用するか、アプリを徹底的に最適化する必要がある場合を除きます。
主に、ビット シフトは次の 2 つの目的で使用できます。

  • 乗算/除算の高速な代替手段として、または乗算/除算できないアーキテクチャで (以下の例を参照)
  • ビットフィールドの値を取得するユーティリティとして ( EVIL )

1 のビット シフトは、2 で除算または 2 で乗算することと同等であり、はるかに高速です。自分でチェックしてください :64>>1==3264<<1==128. 実際、ソフトウェアの乗算/除算の実装は、多くの場合、シフトに基づいています。

ps。わかった。あくまで私の意見です。ビットフィールドはあなたの子供の頃の火事であることは知っていますが、それは単なる意見です.

于 2009-10-20T13:17:11.433 に答える