Анимация
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

+ 1 при и>0.

Однако добавление 1 при положительных значениях п неудобно (так как невозможно просто использовать знаковый бит п), так что вместо этого будет выполняться прибавление 1, если значение q отрицательнр. Эти действия эквивалентны, поскольку сомножитель т отрицателен (как будет показано далее).

Генерируемый для случая W-32, d = -l код показан ниже.

M,0X6DB6DB6D

Магическое число -(2**34+5)/7 +

mulhs

q,M,n

q = floor(M*n/2**32)

q,q,n

q = floor(M*n/2**32) - n

shrsi

q,q,2

q = floor(q/4)

shri

t,q,31

Прибавляем 1 к q, если

q,q,t

q отрицательно (n положительно)

muli

t,q,-7

Вычисляем остаток по формуле

r, n, t

г = п - q* (-7) .

Этот код очень напоминает код для деления на +7, с тем отличием, что он использует множитель для деления на +7, но с обратным знаком, команду вычитания вместо команды умножения, а кроме того, команда сдвига shri использует д, а не и (о чем говорилось ранее). (Заметим, что в случае деления на +7 также можно использовать в качестве операнда q, но при этом код будет иметь меньшую степень параллелизма.) Команда вычитания не может привести к переполнению, поскольку операнды имеют один и тот же знак.

Тем не менее эта схема работает не всегда. Хотя приведенный код для W = 32, </ = -7 вполне корректен, аналогичные изменения кода деления на 3 для получения кода для деления на -3 приведут к неверному результату при W = 32, и = -2".

Рассмотрим ситуацию подробнее.

Пусть дан размер слова W >3 и делитель -2"" <d<-2 и требуется найти наименьшее (по абсолютному значению) целое -2" йтйО и целбе p>W , такие, что

2"

+1 =

для -2-<п<0,

для 1<и<2*

(14,а)

(14,6)

Поступим так же, как и в случае деления на положительный делитель. Пусть п - наибольшее по абсолютной величине отрицательное значение п, такое, что и, = Ы +1 для

некоторого целого к. Такая величина Пс сушествует в силу того, что имеется по крайней мере одно значение n,~d + \. Это значение можно вычислить, исходя из того, что

и, = (-2*"-l)/d d + l = -2""+rem(2""+l,d). Величина п представляет собой одно из

d наименьших допустимых значений и, так что

-2-S«,<-2"--d-l (15,а)

и, очевидно.

и <d + l.

(15,6)



Поскольку (14,6) должно выполняться при n = ~d,& (14,а) - для п-п,,хо аналогично (4) получим

--£-<т<-. (1о)

Так как т является наибольшим целым «ислом, удовлетворяющим (16), оно представляет собой ближайшее целое, меньшее 2jd, т.е.

2-t/-rem(2t/)

(17)

Объединяя это выражение с левой частью (16) и упрощая, получим

(18)

2>л,(t/ + rem(2t/))

Доказательство пригодности предложенного в (17) и (18) алгоритма и корректности произведения выполняется аналогично доказательству для положительного делителя и здесь не приводится. Трудности возникают только при попытках доказать, что -2" < m < О. Для доказательства рассмотрите по отдельности случаи, когда d представляет собой отрицательное число, абсолютное значение которого является степенью двойки Для t/ = -2* можно легко показать, что л„=-2"" + 1, p = W+k-l и т = -2""-1 (которое находится в изначально определяемом диапазоне). Для тех d, которые имеют отличный от -2* вид, достаточно просто изменить доказательство, приведенное ранее, при рассмотрении положительного делителя.

Для каких делителей mi-d)-m(d)7

Под m{d) подразумевается множитель, соответствующий делителю d. Если m(-d)--m{d), код для деления на отрицательный делитель может быть сгенерирован путем вычисления множителя для Щ , изменения его знака и генерации кода, аналогичного коду из примера "деления на -7", проиллюстрированному ранее.

Сравнивая (18),с (6), а (17) с (5), можно увидеть, что если значение для -d представляет собой значение для d, но с обратным знаком, то m{-d) = -m{d). Следовательно, m(-d) Ф -m(d) может быть только тогда, когда значение вычисленное для отрицательного делителя, представляет собой наибольшее по абсолютному значению отрицательное число -2"". Такие делители представляют собой отрицательные сомножители г"" +1. Эти числа встречаются очень редко, что иллюстрируется приведенными ниже разложениями.

21= 3-11-331 241 =3-715827883 2+1 = 3-19-43-5419-77158673929 Для всех этих множителей m{-d)~m{d). Вот набросок доказательства. Для d>0

мы имеем = 2""- rf. Поскольку гет( 2"", rf) = rf-l, значение p = W-\ удовлетворяет (6), а следовательно, этому неравенству удовлетворяет и p = W. Однако для rf < О мы имеем л=-2" и rem(2"",rf) = rf-l. Следовательно, ни p = W-1,hh p = W не удовлетворяют (18), так что p>W.



2"-+rem(2"-,t/)-l, d>0, -2"-+Km{f-+U), d<0.

Следовательно, можно вычислить так;

r = 2

d>0, d<0.

= t-\-Km[t,\d\).

Остаток должен вычисляться с использованием беззнакового деления, в соответствии со значениями аргументов. Здесь используется запись гет(г,г/), а не эквивалентная ей Tem{t,d) именно для того, чтобы подчеркнуть, что программа должна работать с двумя

положительными (и беззнаковыми) аргументами.

Исходя из (6) и (18), значение р может быть вычислено из соотношения

2>K(M-rem(2£)),

(19)

после чего m

можно вычислить следующим образом (используя (5) и (17)): 2 +\d\-Tem{2,\d)

(20)

Непосредственное вычисление rem(2,t/) в (19) требует применения "длинного деления" (деление 2W-6HTOBoro делимого на W-битовый делитель и получение W-битовых частного и остатка), причем это длинное деление должно быть беззнаковым. Однако имеется путь решения (19), который позволяет избежать использования длинного деления и может быть легко реализован в обычных языках программирования высокого уровня с использованием только W-битовой арифметики. Тем не менее нам потребуется беззнаковое деление и беззнаковое сравнение.

Вычислить гет(2,г/) можно инкрементно, инициализируя две переменные диг

значениями частного и остатка от деления 2 на \d\ при р = W -1, а затем обновляя значения g и г по мере роста р.

В процессе поиска при увеличении значения р на 1 значения диг изменяются следующим образом (см. теорему D5 (первая формула)):

q = 2*q; г = 2*г:

if (г >= abs(d))

Для того чтобы компилятор мог заменить деление на константу произведением, он должен вычислить для данного делителя d магическое число М и величину сдвига s. Простейший способ состоит в вычислении (6) или (18) для р = W,W +1,... до тех пор, пока условие будет выполняться. Затем из (5) или (17) вычисляется значение т. Магическое число М представляет собой не что иное, как интерпрепщию т как знакового целого числа, а j = р - W .

Описанная ниже схема обрабатывает положительные и отрицательные d с помощью небольшого дополнительного кода, и позволяет избежать арифметических выражений с двойными словами.

Вспомним, что Пс задается следующим образом;



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