Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 [ 35 ] 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

Листинг 7.7. Действия при использовании метода параллельного префикса для онерации сжатия

abed

efgh

ijkl

mnop

qrst

uvwx

yzAB

CDEF

1000

1000

1110

0000

0000

1111

0101

0101

aOOO

eOOO

i]k0

0000

0000

uvwx

OzOB

ODOF

i = 0,

1110

1110

1111

1110

0001

0101

0100

После

1010

0101

1110

1010

1010

0000

1100

1100

1000

0000

1110

0000

0000

0000

0100

0100

0100

1000

0111

0000

0000

1111

0011

0011

OaOO

eOOO

Oijk

0000

0000

uvwx

OOzB

OODF

1 = 1,

0100

1010

0001

0101

0100

0001

0001

0000

После

1100

Olio

0000

1100

1100

0000

1111

0000

0100

0000

0000

0000

0000

0000

0011

0000

0001

1000

0111

0000

0000

1111

0000

1111

OoOa

eOOO

Oijk

0000

0000

uvwx

0000

zBDF

i = 2,

0000

1000

0001

0001

0000

0001

0000

0000

После

0000

0111

1111

0000

1111

1111

0000

0000

0000

0000

0111

0000

0000

1111

0000

0000

0001

1000

0000

0111

0000

0000

1111

1111

000a

eOOO

0000

Oijk

0000

0000

uvwx

ZBDF

1 = 3,

0000

1000

0000

0001

0000

0000

0000

0000

После

0000

0111

1111

1111

0000

0000

0000

0000

0000

0000

eooo

0111

0000

0000

0000

0000

0001

1000

0000

0000

0000

0111

1111

1111

000a

eOOO

0000

0000

0000

Oijk

uvwx

zBDF

1 = 4,

0000

1000

0000

0000

0000

0000

0000

0000

После

1111

i6oo

0000

0000

0000

0000

0000

0000

0001

1000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0001

1111

1111

1111

0000

0000

0000

0000

000a

eijk

uvwx

zBDF

Алгоритм из листинга 7.6 на 64-битовой машине с базовым RISC-набором выполняется за 169 команд, в то время как алгоритм из листинга 7.5 в худшем случае требует выполнения 516 команд.

Количество команд, выполнения которых требует алгоритм из листинга 7.6, может быть значительно снижено, если m представляет собой константу. Это может быть в двух ситуациях: 1) когда вызов compress (x,m) осушествляется в цикле, в котором значение m не известно заранее, но постоянно в пределах цикла, 2) когда известно значение m и код функции compress генерируется заранее, возможно, компилятором.

Обратите внимание на то, что значение, присвоенное х в цикле в листинге 7.6, используется в этом цикле исключительно в строке, где выполняется присвоение х. Как видно из кода, х зависит только от себя самого и переменной mv. Следовательно, все об-рашения к х можно удалить, а пять вычисляемых значений mv сохранить в переменных mvO, mvl, mv4. Тогда в ситуации 1 вне цикла, в котором имеется обрашение compress (х,т), можно разместить функцию, которая не будет обращаться к х, а будет лишь вычислять значения mvl, а в самом цикле можно разместить следующие строки:

&

&

mvO; X

>>

1) ;

&

mvl; X

>>

2) ;

&

mv2; X

>>

4) ;

&

mv3; X

>>

8) ;

&

mv4; X

>>

16);



Таким образом, вычисления в цикле состоят из 21 команды (загрузка констант выносится за пределы цикла), что является значительным улучшением по сравнению со 127 командами, необходимыми в случае полной подпрограммы из листинга 7.6.

В ситуации 2, в которой известно значение т, можно выполнить примерно те же действия, не считая другой возможной оптимизации. Так, может оказаться, что одна из пяти масок равна О, и в этом случае можно опустить одну из приведенных выше строк. Например, если нет битов, которые должны быть перемещены на нечетное число позиций, маска ml равна 0; если нет битов, которые перемещаются более чем на 15 позиций, равной О окажется маска т4.

Так, для

m = 0101 0101 0101 0101 0101 0101 0101 0101 вычисленные маски равны

mvO =

0100

0100

0100

0100

0100

0100

0100

0100

mvl =

0000

0000

0000

0000

mv2 =

0000

1111

0000

0000

0000

0000

0000

mv3 =

0000

0000

1111

0000

0000

0000

0000

mv4 =

0000

0000

0000

0000

0000

0000

0000

0000

Поскольку последняя маска равна О, в скомпилированном коде операция сжатия выполняется за 17 команд (не считая команд для загрузки масок). Конечно, имеются еще более специализированные случаи, в часгаости код из раздела 7.2, в котором сжимаются чередующиеся биты, выполняется всего за 13 команд.

Использование команд вставки и извлечения

Если ваш компьютер имеет команду вставки (insert), причем предпочтительно с непосредственно задаваемыми значениями в качестве операндов, которые определяют битовое поле в целевом регистре, то она может использоваться для выполнения операции сжатия с меньшим числом команд, чем в описанном выше методе. Кроме того, при этом не накладываются ограничения на использование регистров, хранящих маски.

Целевой регистр инициализируется нулевым значением, после чего для каждой непрерывной группы единичных битов в маске m переменная х сдвигается вправо для выравнивания очередного поля и используется команда вставки, которая вставляет биты х в соответствующее место целевого регистра. Таким образом операция сжатия выполняется с помощью 2п +1 команд, где п - количество полей (групп единичных битов) в маске. В наихудшем случае требуется выполнить 33 команды, так как максимальное число полей равно 16 (случай чередования единичных и нулевых битов).

В качестве примера, когда метод с использованием команды вставки дает существенный выигрыш, рассмотрим т=0х001(Ю84А. Сжатие с такой маской требует перемещения битов на 1, 2, 4, 8 и 16 позиций. Следовательно, при использовании метода параллельного префикса требуется выполнение всех 21 команды, в то время как при использовании вставки достаточно 11 команд (в маске имеется пять полей). Еще более удачным примером может служить маска т=0х8О(ХЮО0О. Здесь происходит перемещение одного бита на 31 позицию, что требует выполнения 21 команды в методе параллельного префикса, только трех команд при использовании вставки и только одной команды (сдвиг вправо на 31 бит), если вы не ограничены определенной схемой вычислений.

Можно также воспользоваться командой извлечения (extract) для реализации операции сжатия посредством выполнения Зп -2 команд, где п - количество полей в маске.



Совершенно ясно, что создание оптимапьного кода, реализующего сжатие для заранее известной маски, представляет собой далеко не тривиальную задачу.

Сжатие влево

Очевидным путем решения этой задачи является реверс аргумента х и маски т, выполнение сжатия вправо и реверс полученного результата. Еще один способ решения состоит в сжатии вправо с последующим сдвигом влево на pop(»i) позиций. Эти решения

наиболее приемлемы, если ваш компьютер имеет команды реверса или подсчета количества единичных битов. Если же таких команд в наборе компьютера нет, можно легко адаптировать алгоритм из листинга 7.6, просто изменив направление всех сдвигов на обратное (за исключением двух сдвигов в выражениях l<<i, всего восемь изменений).

7.5. Обобщенные перестановки

При выполнении обобщенной перестановки битов в слове (или где-либо еще) главной проблемой становится представление перестановок. Очень компактно представить перестановку невозможно. Поскольку в 32-битовом слове можно выполнить 32! перестановки, для указания одной из них требуется, как минимум, ["log2(32!)] = U8 битов, или 3 слова и еще 22 бита.

Один интересный способ представления перестановок тесно связан с операцией сжатия, рассматриваемой в разделе 7.4 [19]. Начнем с непосредственного метода, в котором для каждого бита просто указывается позиция его перемещения. Например, для перестановки, которая выполняется путем циклического сдвига влево на четыре бита, бит в позиции О (младший бит) переместится в позицию 4, в позиции 1 - в позицию 5, в позиции 31 - в позицию 3. Такая перестановка может быть представлена следующим вектором из 32 пятибитовых индексов:

00100 00101

11111 ооооо

00001 00010 00011

Рассматривая это представление как битовую матрицу, транспонируем ее так, чтобы при этом верхняя строка содержала младшие биты, а результат представим в формате, когда младший бит располагается справа. Таким образом будет получен массив из пяти 32-битовых слов.

р[0]

1010

1010

1010

1010

1010

1010

1010

1010

р[1]

1100

1100

1100

110О

1100

1100

1100

1100

р[2]

0000

1111

0000

1111

0000

1111

0000

1111

р[3]

0000

1111

1111

0000

0000

1111

1111

0000

р[4]

0000

1111

1111

1111

1111

0000

0000

0000

Каждый бит в р [0] представляет собой младший бит позиции, в которую переносится соответствующий бит исходного слова х, биты в р [1] представляют собой следующий значащий бит и т.д. Это очень похоже на то, как маска m в предыдущем разделе ко-



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 [ 35 ] 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87