2013-07-25 2 views
3

Я stuying этот код, и я не понимаю, что делает эта линия: [(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

[Побитовое и смещение операторов резюме] (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/opsummary.html) – BackSlash

+3

Похоже, что это индексирование в 2D-массив, хранящийся в одном массиве. –

+0

@DaveNewton Я думаю, что это он! – user2520410

ответ

3

(y << 3) означает смещение бит 3 раза влево. Это то же самое, что умножение на 2^3 = 8. Таким образом, целое выражение (y << 3) + x становится y * 8 + x.

Он должен быть записан в форме y * 8 + x, потому что он более читабельный и, вероятно, нет увеличения производительности. Premature optimization is the root of all evil. Лучше оставить такие микро оптимизации для компилятора (или JVM).

Кроме того, размер платы может быть сохранена в постоянной, чтобы он только в одном месте:

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 + x просто итерацию над (логически) 2D таблицы с 8 строк и столбцов, хранится в виде 1D , с 64 ячейками.

В качестве последнего замечания, я хотел бы отметить, что в данном коде pieceCodes это массив строк ... Но на самом деле, это массив штучных кодов. Не только некоторые Струны. Теперь "--" работает как какое-то волшебное состояние, и никто, кроме программиста, не знает, что это значит. if (pieceCode.length() != 2) также выглядит плохо. Таким образом, должен быть объект PieceCode, и массив будет объявлен как PieceCode[] pieceCodes. В PieceCode мы можем реализовать правильный метод equals(). Если PieceCode - это только состояние, это может быть Enum. Например, EMPTY, WHITE_PAWN, WHITE_QUEEN, BLACK_PAWN, BLACK_QUEEN. Сравнение строк не так быстро, как сравнение Enums. Мы также должны следить за тем, чтобы написать equals(), а не ==.

6

Это нечитаемом способ умножения на 8. Таким образом, (y << 3) + x равно до 8 * y + x.

Причина, по которой y << 3 эквивалентно умножению на 8 происходит потому, что << является оператором сдвига влево: она сдвигает все биты y влево на одну позицию. Точно так же, если вы берете номер базы-10 и сдвигаетесь влево на одну позицию, у вас есть умножение на 10, смещение влево в базе-2 эквивалентно умножению на 2. Следовательно, сдвиг влево на три позиции эквивалентен умножению на 2 * 2 * 2 = 8. В общем, сдвиг влево на n позиций эквивалентен умножению на 2^n (если у вас нет бит, падающего с левого конца).

В старые времена программисты написали такой код, потому что левые смены супер пуперы быстрее, чем умножение, и поэтому 8 * y был менее оптимальным, чем y << 3. Но в наши дни компиляторы очень хорошо разбираются, когда нужно заменить что-то вроде 8 * y на y << 3.

Поэтому я говорю это потому, что запутывание 8 * y более четко выражает намерение: намерение (y << 3) + x это пропустить по y блоков 8, и занять позицию x-й в этом блоке. И это много более четко выражено выражением 8 * y + x. Помните, мы кодируем языки высокого уровня для людей, чтобы читать и понимать код. Наш код должен быть написан для людей. Компилятор может выполнять свою работу по созданию хороших машинных инструкций для понимания машиной.

Это делается так, потому что он пытается притвориться, что pieceCodes - это 2D-массив, который просто отображается в 1D-массив.

То есть, 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 мы доступ к x-й столбец, y-й строки piecesCode. То есть y сообщает нам, сколько блоков из 8 пропустить, а x рассказывает нам, куда идти в этом блоке.

+3

Это не обязательно запутывается. –

+4

Я уже достаточно взрослый, это не обфускация :( –

+1

конкретно, '(y << n) + x' эквивалентно' (y * (2^n)) + x' –

1

Быстрый ответ, это эффективный способ умножения числа на 8 (2^3 = 8)

+1

Почему это эффективно? – NINCOMPOOP

+0

Я действительно сомневаюсь, что переключение происходит быстрее, чем умножение на 8. Кроме того, это менее читаемо. – f1sh

+0

Это вряд ли будет значительно более эффективным. В тот же день код операции «сдвиг-на-два» был быстрее, чем общий многократный код операции, т. Е. Было быстрее умножить на две силы, сдвинув и добавив, чем использовать умножение. –

1

< < у 3 означает «сдвинуты 3 бита влево» ... который, по сути, еще один способ do "* 8"

Если вы выполняете правую смену (y >> 3), то это будет целое число на восемь, но также полезно, потому что бит падает с конца, и вы вроде как " бит, если вы зацикливаете.

Раньше это было (путь назад, когда), что сдвиг ЦП был быстрее, чем умножение, поэтому использование «x < < 1» было быстрее, чем «x * 2». Однако это не так.

Я привык видеть выражения в коде, как "х < < 4 + х < < 2 + х < < 1" ... что на самом деле "х * 16 + х * 4 + х * 2" или «х * 22 ".

2

Из спецификации:

Значение п < < с п является левым смещенной с позиции битов; это эквивалентно (даже если происходит переполнение) для умножения на два на степень s.

2

< < и >> являются операторами сдвига бит. В этом случае, он преобразует у в двоичные и «сдвиги» более 3 места, добавляя новые биты к концу в соответствии с требованиями

Например, если у было 8, это будет иметь значение 1000

у < < 3 будет сдвигаться влево на 3 бита, в результате получается 1000000 или 64

2

В коде используется метод оптимизации, представляющий двумерный массив [m] [n] как одномерный массив [m * n]. И m, и n, кажется, здесь 8 (8-королевы, шахматы, может быть?).

Трюк заключается в переносе индексных кортежей (i, j) на индексы для одномерного массива.

В большинстве случаев вы делаете это, умножая i на n и добавляя j.

Поскольку n = 8, умножение можно выразить в этом случае, сдвинув 3 бита влево. Это передает сообщение «Мы делаем арифметику адресатов здесь по некоторым красивым размерам (т. Е. По мощности 2) массивов». По крайней мере, для новичков.

+2

Я бы догадался о шагах, потому что 'CheckersPiece'. Просто догадка. –

+0

@DaveNewton Скорее всего, да. Не читал так далеко :) – Ingo

+1

Я не понимаю, почему все считают, что оптимизация оптимизирована. В моем коде я использую его для ясности: чтобы подчеркнуть двоичную округлость числа, о котором идет речь. '1 << 31', например, является более простым, понятным и более очевидным, чем' 2147483638'. –

2

Это называется bitwise and bit shift operator. Также проверьте wiki.

Резюме документации

Язык программирования Java также предоставляет операторам, которые выполняют побитовое и бит сдвига операций на целочисленных типах. Обсуждаемые в этом разделе операторы реже используются.

Унарный побитовый оператор дополнения «~» инвертирует бит-шаблон. Подписанный оператор сдвига влево «< <» сдвигает бит влево, а сдвинутый сдвиговый оператор «>>» сдвигает бит вправо.

Побитовый оператор & выполняет побитовое И операцию.

Оператор bitwise^выполняет побитовое исключающее ИЛИ операцию.

Побитовый | оператор выполняет побитовое включение операции ИЛИ.

Пример кода:

class BitDemo { 
    public static void main(String[] args) { 
     int bitmask = 0x000F; 
     int val = 0x2222; 
     // prints "2" 
     System.out.println(val & bitmask); 
    } 
} 

Итак ... Что такое оператор побитовое и побитового сдвига?

Чтобы сэкономить время и пространство, я просто включу этот article, объясняя все операторы в глубину!

+2

Похоже на совершенно несвязанный пример и кучу слов, которые описывают другие вещи. –

+0

Да, оставаться в теме - это глупая идея. Сожалею. –

+0

Эй, я просто пытаюсь помочь. – Scientious

1

http://en.wikipedia.org/wiki/Bitwise_operation ... В Java все целые типы подписаны, а операторы «<» и «>>» выполняют арифметические сдвиги. Java добавляет оператор «>>>» к выполнению логических сдвигов вправо, но поскольку логические и арифметические операции с левым сдвигом идентичны, в Java нет оператора «< < <».

Смежные вопросы