3

私はこのコードを勉強していますが、この行が何をするのか理解できません:[(y << 3) + x]

    for (int y = 0; y <= 7; ++y) {
            for (int x = 0; x <= 7; ++x) {
                final String pieceCode = pieceCodes[(y << 3) + x];
                if (pieceCode.length() != 2) throw new IllegalArgumentException();
                if (!pieceCode.equals("--")) {
                    pieces[((7 - y) << 3) + x] = CheckersPiece.valueOf(pieceCode.charAt(0), pieceCode.charAt(1));   
                }
            }
        }
4

9 に答える 9

6

これは難読化された 8 倍の方法です。したがって、(y << 3) + xは に等しくなり8 * y + xます。

8 を掛けることy << 3と同等である理由<<は、 が左シフト演算子であるためです。これは、左のすべてのビットをy1 桁シフトします。基数 10 の数値を左に 1 桁シフトすると 10 を掛けることができるのと同じように、基数 2 を左にシフトすることは 2 を掛けることと同じです。したがって、左に 3 桁シフトすることは、 2 * 2 * 2 = 8. 一般に、n位置を左にシフトすることは、乗算することと同じ2^nです (左端からビットが落ちない限り)。

昔、プログラマーはこのようなコードを書きました。なぜなら、左シフトは非常に高速で、乗算よりも高速であり8 * yy << 3. しかし、最近では、コンパイラ8 * yy << 3.

したがって、意図をより明確に表現しているため、難読化されていると言います8 * y。 の意図は、8 のブロックで(y << 3) + xスキップし、そのブロックで th の位置を取ることです。そして、これはと言うとより明確に表現されます。人間がコードを読んで理解できるように、高水準言語でコーディングしていることを忘れないでください。私たちのコードは人間のために書かれるべきです。コンパイラは、マシンが理解できるように適切なマシン命令を作成するという仕事を行うことができます。yx8 * y + x

pieceCodesこれは、1D 配列にマップされたばかりの 2D 配列であるふりをしようとしているためです。

つまり、piecesCodeこんな感じ

x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x

しかし、このように見えるふりをすることができます

x x x x x x x x 
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x

の番目の列、番目の行に(x, y) -> 8y + xアクセスするとします。つまり、スキップする 8 のブロックの数と、そのブロック内のどこに移動するかを示します。xypiecesCodeyx

于 2013-07-25T15:28:07.677 に答える
3

(y << 3)左に 3 回ビットシフトすることを意味します。2^3=8をかけるのと同じなので、式全体(y << 3) + xは となりy * 8 + xます。

の形式で記述する必要があります。これはy * 8 + x、読みやすく、おそらくパフォーマンスが向上しないためです。時期尚早の最適化は諸悪の根源です。このようなマイクロ最適化は、コンパイラ (または JVM) に任せたほうがよいでしょう。

さらに、ボードのサイズを定数に格納して、1 か所だけにすることもできます。

final int SIZE = 8;
// ...
for (int y = 0; y < SIZE; y++) {
    for (int x = 0; x < SIZE; x++) {
        final String pieceCode = pieceCodes[y * SIZE + x];

y * 8 + x8行と8列の(論理的に)2Dテーブルを1Dとして格納し、64個のセルを反復処理しています。

最後の注意として、与えられたコードは文字列の配列であることを指摘したいと思いpieceCodesます...しかし、実際には、ピース コードの配列です。一部のストリングスだけではありません。現在、"--"何らかの魔法の状態として機能し、プログラマー以外の誰もそれが何を意味するのかを知りません。if (pieceCode.length() != 2)見た目も悪い。したがって、オブジェクトが存在する必要がありPieceCode、配列は として宣言されPieceCode[] pieceCodesます。では、適切なメソッドPieceCodeを実装できます。equals()が状態のみの場合PieceCodeは、Enum にすることができます。たとえばEMPTY, WHITE_PAWN, WHITE_QUEEN, BLACK_PAWN, BLACK_QUEEN。文字列の比較は、列挙型の比較ほど高速ではありません。equals()の代わりに ,と書くことにも注意する必要があり==ます。

于 2013-07-25T15:28:47.460 に答える
2

仕様から:

n << s の値は、n 左シフトされた s ビット位置です。これは、(オーバーフローが発生した場合でも) 2 の s 乗と同じです。

于 2013-07-25T15:30:07.093 に答える
2

<< と >> はビット シフト演算子です。この場合、y をバイナリに変換し、必要に応じて末尾に新しいビットを追加して、3 桁にわたって「シフト」します。

たとえば、y が 8 の場合、値は 1000 になります。

y<<3 は左に 3 ビットシフトし、1000000 または 64 になります。

于 2013-07-25T15:31:14.330 に答える
2

このコードは、2 次元配列 [m][n] を 1 次元配列 [m*n] として表す最適化手法を使用しています。ここでは、m と n の両方が 8 のように見えます (8 クイーン、チェス、おそらく?)。

トリックは、インデックス タプル (i,j) を 1 次元配列のインデックスに転置することです。

ほとんどの場合、これを行うには、i に n を掛けて j を足します。

n=8 なので、この場合の乗算は 3 ビット左シフトすることで表現できます。これは、少なくとも初心者以外には、「適切なサイズの (つまり、2 の累乗で) 配列でアドレス演算を行っている」というメッセージを伝えます。

于 2013-07-25T15:31:55.497 に答える
1

http://en.wikipedia.org/wiki/Bitwise_operation ... Java では、すべての整数型が符号付きで、"<<" および ">>" 演算子が算術シフトを実行します。Java は演算子 ">>>" を追加して論理右シフトを実行しますが、論理および算術左シフト演算は同じであるため、Java には "<<<" 演算子はありません。

于 2013-07-25T15:35:49.183 に答える
1

簡単な答えです。これは、数値に 8 を掛ける効率的な方法です (2^3=8)。

于 2013-07-25T15:29:47.270 に答える
1

y << 3 は、「3 ビット左にシフト」を意味します ... これは、基本的に、「* 8」を行う別の方法です

右シフト (y >> 3) を行う場合、それは整数の 8 除算になりますが、ビットが最後から外れ、ループするとビットを「ドレイン」するので便利です。

CPUシフトが乗算よりも高速だったのは(ずっと前のことですが)、「x << 1」を使用すると「x * 2」よりも高速でした。しかし、それはもはや真実ではありません。

「x << 4 + x << 2 + x << 1」のようなコードの式を見たことがあります...これは、実際には「x * 16 + x * 4 + x * 2」または「x * 22」です。

于 2013-07-25T15:29:53.723 に答える