私はC#でシフト演算子を研究していて、コードでそれらをいつ使用するかを見つけようとしていました。
私は答えを見つけましたが、Javaの場合は次のことができます。
a)作成高速整数の乗算および除算演算:
* 4839534 * 4 *は次のように実行できます:4839534 << 2
または
543894/2は次のように実行できます:543894 >> 1
ほとんどのプロセッサでは、乗算よりもはるかに高速に演算をシフトします。
b)バイトストリームをint値に再アセンブルします
c)赤、緑、青の色は別々のバイトでコード化されているため、グラフィックスを使用した操作を高速化できます。
d)小さな数を1つの長いものに詰め込む...
B、c、dについては、ここで実際のサンプルを想像することはできません。
これらすべての項目をC#で実行できるかどうか誰かが知っていますか? C#でシフト演算子のより実用的な使用法はありますか?
コンパイラがこれを自動的に処理するため、最適化の目的でそれらを使用する必要はありません。
ビットをシフトすることがコードの本当の目的である場合にのみ使用してください(質問の残りの例のように)。残りの時間は、乗算と除算を使用するだけなので、コードの読者はそれを一目で理解できます。
非常に説得力のある理由がない限り、私の意見では、そのような巧妙なトリックを使用すると、通常、付加価値がほとんどない、より混乱したコードが作成されます。コンパイラーの作成者は賢い開発者であり、平均的なプログラマーよりも多くのトリックを知っています。たとえば、整数を2の累乗で除算する方が、シフト演算子を使用すると除算よりも高速ですが、コンパイラが自動的に行うため、おそらく必要ありません。これは、Microsoft C/C++コンパイラとgccの両方がこれらの最適化を実行するアセンブリを見るとわかります。
私が過去に遭遇した興味深い使用法を共有します。この例は、質問に対する補足回答から恥知らずにコピーされています。 " [Flags] Enum AttributeはC#で何を意味しますか? "
[Flags]
public enum MyEnum
{
None = 0,
First = 1 << 0,
Second = 1 << 1,
Third = 1 << 2,
Fourth = 1 << 3
}
これは、リテラル1, 2, 4, 8, ...
値を書き込むよりも、特に17個を超えるフラグを取得した場合に拡張する方が簡単です。
トレードオフとして、31を超えるフラグ(1 << 30
)が必要な場合は、列挙型を符号付き整数よりも高い上限を持つものとして指定するように注意する必要があります(public enum MyEnum : ulong
として宣言することにより)。たとえば、最大64個のフラグが表示されます)。それの訳は...
1 << 29 == 536870912
1 << 30 == 1073741824
1 << 31 == -2147483648
1 << 32 == 1
1 << 33 == 2
対照的に、列挙値を直接2147483648に設定すると、コンパイラはエラーをスローします。
ClickRickが指摘しているように、列挙型がulongから派生している場合でも、ビットシフト操作をulongに対して実行する必要があります。そうしないと、列挙型の値が壊れます。
[Flags]
public enum MyEnum : ulong
{
None = 0,
First = 1 << 0,
Second = 1 << 1,
Third = 1 << 2,
Fourth = 1 << 3,
// Compiler error:
// Constant value '-2147483648' cannot be converted to a 'ulong'
// (Note this wouldn't be thrown if MyEnum derived from long)
ThirtySecond = 1 << 31,
// so what you would have to do instead is...
ThirtySecond = 1UL << 31,
ThirtyThird = 1UL << 32,
ThirtyFourth = 1UL << 33
}