УДК 519.6 Х. Рамиль Альварес АЛГОРИТМЫ ДЕЛЕНИЯ И ИЗВЛЕЧЕНИЯ КВАДРАТНОГО КОРНЯ В ТРОИЧНОЙ СИММЕТРИЧНОЙ СИСТЕМЕ (лаборатория ЭВМ факультета ВМиК, e-mail: ramil@cs.msu.su) Предложена модификация алгоритма деления Брусенцова для троичной симметричной системы, основанный на использовании половины модуля делителя. Рассмотрен алгоритм извлечения квадратного корня в этой системе на базе известного метода в "столбик" и применения алгоритма деления. В работах [1, 2], в которых описана созданная в 1840 г. английским изобретателем Томасом Фаулером троичная механическая вычислительная машина, приведены примеры деления в троичной симметричной системе. Однако в них не рассмотрены самые тонкие моменты процесса, вследствие чего их нельзя считать описанием алгоритма. Поэтому следует признать, что первые алгоритмы точного вычисления частного в троичной симметричной системе предложены Брусенцовым Н.П. в [3]. Алгоритмы деления предполагают, что значения делимого и делителя - нормализованные троичные числа, определенные в [4], т.е. равны нулю или их абсолютные величины принадлежат интервалу (0.5 ; 1.5). 1. Модификация алгоритма деления Брусенцова. Рассмотрим первый из предложенных алгоритмов [3] division1, результат которого выдается в виде пары чисел: нормализованной мантиссы е и порядка q, соответствующих представлению частного в виде e⋅3 q . Точность, с которой вычисляется мантисса e, задается целочисленным параметром k, указывающим количество троичных разрядов в представлении e. procedure division1 (c, d, e, q, k); value k; integer k, q; real c, d; integer array e; comment с - делимое и d - делитель равны нулю или их абсолютные величины принадлежат интервалу (0.5 ; 1.5). Частное представляется посредством мантиссы е[1 : k] и порядка q в виде 3 q ⋅Σ e p ⋅3 1-p; begin integer p; se, sd; real g; prepare (c, d, e, q, k, sd); comment Обнуление массива e. Удвоение делимого (c) и вычисление модуля (d) и знака (sd) делителя d; for p := 1 step 1 until k begin if c > 0 then sc := 1 else sc := -1; g := c * sc - d ; if g > 0 then begin e[p] := sc * sd ; c := (g - d) * sc end; c := c * 3 end end division1; Приведем описание процедуры prepare, которая заранее определяет значение порядка q и корректирует значение делимого с или делителя d так, что вычисляемая мантисса частного e получается нормализованной: procedure prepare (с, d, e, q, k, sd); value k; integer k, q, sd; integer array e; real c, d; comment Оператор stop прерывает процедуру, если d=0; begin integer p; if d > 0 then sd := 1 else if d < 0 then sd := -1 else stop; d := abs(d); с := c + c; for p:= 1 step 1 until k do e[p] := 0; if abs(c) - d * 3 > 0 then begin q := l; d := d * 3 end else if abs(c) - d > 0 then q:= 0 else begin q := -1; c:= c * 3 end end prepare; Отметим, что в алгоритме используется удвоенное значение делимого, из которого на каждом шаге вычитается делитель и результат сравнивается с нулем и при необходимости из результата снова вычитается делитель. Предлагаемая модификация алгоритма (процедура terndiv) основана на том, что первоначально вычисляется половина делителя и в дальнейшем на каждом шаге производится сравнение промежуточного делимого с этой половиной делителя и при необходимости из делимого производится вычитание полного делителя. procedure terndiv (c, d, e, q, k); value k; integer k, q; integer array e; real c, d; comment с - делимое, d - делитель, равны нулю или их абсолютные величины принадлежат интервалу (0.5 ; 1.5). Частное представляется посредством мантиссы е[1 : k] и порядка q в виде 3 q ⋅ Σ ep ⋅3 1-p ; begin integer i, sc, sd; real m; prepare1 (c, d, e, q, k, sd); comment Обнуление массива e. Вычисление модуля (d) и знака (sd) делителя d. Вычисление m, равного половине модуля делителя d; for i := 1 step 1 until k do begin if c < 0 then sc := -1 else sc := 1; if compar(c, sc, m) > 0 then comment compar - сравнение с и m с учетом знака sc, т.е. sign(c * sc - m); begin e[i] := sc * sd; c := c - sc * d end ; c := c * 3 end end terndiv ; Процедура prepare1 по сравнению с процедурой prepare включает вычисление половины модуля делителя. Следует отметить, что процедура compar(c, sc, m) – сравнение с и m с учетом знака sc, т.е. sign(c * sc - m) сводится к поразрядному сравнению слева направо до первого несовпадающего, что существенно проще, чем вычитание. procedure prepare1 (с, d, e, q, k, sd); value k; integer k, q, sd; integer array e; real c, d; comment Оператор stop прерывает процедуру, если d=0; begin integer p; if d > 0 then sd := 1 else if d < 0 then sd := -1 else stop; d := abs(d); media (d, m, k); comment Вычисление m, равного d/2; for p:= 1 step 1 until k do e[p] := 0; if abs(c) - m * 3 > 0 then begin q := l; d := d * 3; m := m * 3 end else if abs(c) - m > 0 then q:= 0 else begin q := -1; c:= c * 3 end end prepare1; Приведем описание процедуры получения половины делителя (m = d/2) для троичной симметричной системы. Алгоритм деления на 2 является частным случаем общего алгоритма деления. При этом учитывается то, что d>0 и не требуется вычислять половину делителя, так как это 1. Описание процедуры media (d, m, k) лучше привести в предположении, что операнд d и результат m являются массивами тритов. procedure media (d, m, k); value k; integer k; integer array d, m; comment Для d принадлежит интервалу (0.5 ; 1.5); begin integer i, sd, di; for i := 1 step 1 until k do m[i] := 0; di := 0; for i := 1 step 1 until k do begin di := di * 3 + d[i]; if di < 0 then sd := -1 else sd := 1; if sd * di > 1 or (sd * di = 1 and sign (d, i+1) = sd) then comment Функция sign (d, i+1) определяет знака числа d, начиная с (i+1)-го разряда; begin m[i] := sd; if sd > 0 then di := di - 2 else di := di + 2 end end; end media; 2. Алгоритм извлечения квадратного корня. Рассмотрим алгоритм извлечения квадратного корня известным методом в "столбик" [5]. Использование алгоритма деления в алгоритме извлечения квадратного корня позволяет упростить его. Приведем алгоритм извлечения квадратного корня для системы счисления с основанием S и с неотрицательными значениями цифр от 0 до S–1. Предварительно подкоренное выражение N разбивается на пары цифр влево и вправо от запятой. Обозначим через Ni – целое число, получаемое из первых слева направо i пар цифр, Ai – целое значение корня из этого числа, Di – i-я пара цифр, di – значение i-й цифры результата. Алгоритм извлечения квадратного корня в "столбик" можно описать следующими формулами: Ni = Ai2 + Bi , B1 = D1 – d12 , A1 = d1 , Bi+1 = (Bi⋅S2 + Di+1 ) – (2⋅Ai⋅S + di+1)⋅di+1 , Ai+1= Ai⋅S + di+1 , где di+1 – наибольшее значение, при котором Bi+1 неотрицательно. Отметим, что действия производятся над целыми числами, а запятая в результате будет поставлена после k-й цифры, если в подкоренном выражении она стояла после k-й пары. Приведенные формулы были использованы в [6] для разработки двоичного устройства извлечения квадратного корня. Заметим, что (Bi⋅S2 + Di+1) при ручном использовании алгоритма является приписыванием справа к значению Bi двух цифр пары Di+1, а 2⋅Ai⋅S + di+1 и Ai⋅S + di+1 – приписыванием цифры di+1 к числам соответственно 2⋅Ai и Ai. Для троичной симметричной системы (S=3) и аналогично тому, как это делается в алгоритме деления, сводя к выбору на каждом шаге между 0 и 1, формулы для вычисления квадратного корня можно записать в виде Ci+1' = Bi⋅32 + Di+1 , Ci+1 = |Ci+1'| – 2⋅Ai⋅3⋅di+1 – di+1'2 , где di+1' равно 0 или 1, Bi+1= Ci+1⋅sign(Ci+1') , di+1= sign(Ci+1')⋅di+1' , Ai+1= Ai⋅3 + di+1 , Формулу для Ci+1 можно записать при di+1' ,равном 1, в виде Ci+1 = (|Ci+1'|–1)– 2⋅Ai⋅3⋅di+1' , Отсюда di+1' есть частное от деления |Ci+1'|–1 на 2⋅Ai⋅3, т.е. вследствие алгоритма деления в троичной системе di+1' равно единице, если 2⋅(|Ci+1'|–1) ≥ 2⋅Ai⋅3, или проще |Ci+1'| > Ai⋅3. Однако в случае |Ci+1'| = Ai⋅3 имеем Ci+1 = |Ci+1'| – 2⋅Ai⋅3⋅½ – (½)2 Поэтому, если ni+1 (остаток необработанной части числа N, рассматриваемой как число с запятой перед первой цифрой) больше ¼, то необходимо принять значение di+1' равным единице. Равенство невозможно, так как ¼ в троичной симметричной системе точно не представимо. Описание процедуры вычисления квадратного корня приведено в предположении, что операнд a и результат b являются массивами тритов. procedure ternsqrt (a, b, k, l); value a, k, l; integer k, l; integer array a, b; comment Вычисление квадратного корня a[1: k] - b[1: l], принадлежат интервалу (0.5 ; 1.5) или равны нулю и представляются посредством мантиссы m[1 : n] в виде Σ mi⋅3 1-i,, m1 = 1; begin integer i, j, ls, sc, g; ls := 0; b[1] := 1; for i := 1 step 1 until l-1 do begin ls := ls * 9 ; j := 2 * i; if j ≤ k then ls := ls + a[j] * 3; if j+1 ≤ k then ls := ls + a[j + 1]; if ls < 0 then sc := -1 else sc := 1; g := ls * sc - tern(i) * 3 ; comment tern(i)- функция вычисления значения массива b, с 1-го по i-й разряды, как целого; if g > 0 or (g = 0 and trinary(i + 1) > 0.25) then comment trinary(i)- функция вычисления остатка массива a, начиная с i-го разряда, как дробного; begin b[i + 1] := sc; ls := (g - tern(i) * 3) * sc -1 end else b[i + 1] :=0; end end ternsqrt ; Реализация функций tern(i) и trinary(i) очевидна. Следует заметить, что выражение trinary(i+1)>0.25 может быть реализовано как последовательное сравнение пары k-го и (k+1)-го тритов массива a с 11 (1 обозначает трит, равный минус единице) до первого несовпадения и знак этой разницы и будет значением выражения. СПИСОК ЛИТЕРАТУРЫ 1. Glusker M., Hogan D., Vass P. The ternary calculating machine of Thomas Fowler // IEEE Annals of the History of Computing. 2005. 27. N. 3. P. 4–22. 2. http://www.mortati.com/glusker/fowler/ternary.htm 3. Брусенцов Н.П. Алгоритмы деления для троичного кода с цифрами 0, 1, –1 // Вычислительная техника и вопросы кибернетики. Вып. 10. Л.: Изд–во ЛГУ, 1974. С. 39–44. 4. Брусенцов Н.П., Маслов С.П. и др. Малая цифровая вычислительная машина "Сетунь". – М.: Изд–во МГУ, 1965. 5. Гусев В.А, Мордкович А.Г. Математика: Справочные материалы. М.: Просвещение, 1990. 6. Карцев М.А. Арифметика цифровых машин. М.: Наука, 1969. Поступила в редакцию 10.09.07 Опубликовано в: Вестн. Моск. ун-та. Сер. 15. Вычислительная математика и кибернетика. 2008. № 2. С. 42-45. На английском языке: J. Ramil Alvarez Algorithms of division and square root extraction in balanced ternary system // Moscow University Computational Mathematics and Cybernetics, Volume 32, Number 2, 2008. Pp. 103-107