Вы находитесь на странице: 1из 42

Московский Государственный Технический

Университет имени Н.Э. Баумана

факультет “Информатика и системы управления”

Материалы для самостоятельного изучения


по теме
“Двоичная арифметика”

по курсу
“Прикладная теория цифровых автоматов”

Составитель: Федоров С.В.

Москва
2020
Содержание
1. Представление чисел в цифровых системах ................................................................................... 3
1.1. Системы счисления ..................................................................................................................... 3
1.2. Представление чисел со знаком. ................................................................................................ 4
1.3. Прочие коды ................................................................................................................................. 6
1.4. Сложение и вычитание чисел без знака и в дополнительном коде......................................... 9
2. Представление чисел с дробной частью ......................................................................................... 12
2.1. Представление чисел с фиксированной запятой .................................................................... 12
2.2. Представление чисел с плавающей запятой............................................................................ 14
3. Умножение двоичных чисел............................................................................................................ 17
3.1. Сдвиги ........................................................................................................................................ 17
3.2. Умножение ”столбиком” .......................................................................................................... 18
3.3. Умножение чисел большой разрядности................................................................................. 20
3.4. Умножение. Формирование частичных произведений. ......................................................... 22
3.5. Умножение. Алгоритм Бута. .................................................................................................... 24
3.6. Умножение. Дерево Уоллеса. ................................................................................................... 28
4. Деление двоичных чисел ................................................................................................................. 33
4.1. Деление ”столбиком” ................................................................................................................ 33
4.2. Деление без восстановления остатка ....................................................................................... 34
4.3. Деление. Дополнительные алгоритмы. ................................................................................... 36
4.4. Метод Ньютона для деления. ................................................................................................... 37
4.5. Метод Ньютона для вычисления квадратного корня. ............................................................ 39
4.6. Применение таблицы начальных приближений. .................................................................... 40
4.7. Метод разложения в ряд ........................................................................................................... 40
Литература ............................................................................................................................................ 42

2
1. Представление чисел в цифровых системах

1.1. Системы счисления

Система счисления - совокупность приемов и правил записи чисел цифровыми


знаками.

Существуют позиционные и непозиционные системы счисления. В


непозиционных системах счисления значение символа не определяется целиком
его положением в записи числа. Например, запись римскими цифрами.

В позиционных системах счисления имеет место соотношение Bi=q•Bi-1, где q -


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

Вес i-го разряда определяется как Pi=qi/q0 = qi - основание системы счисления,


возведенное в степень, соответствующую номеру разряда.

В позиционных системах счисления значение положительного числа


определяется полиномом xn-1•qn-1+xn-2•qn-2+…+x1•q1+x0•q0. Например,
276=2•102+7•101+6•100.

Фиксированным количеством разрядов можно представить ограниченный


диапазон чисел - например, трехразрядным десятичным числом можно
представить числа от 0 до 999. Диапазон представления чисел (диапазон
разрядной сетки) - интервал числовой оси между максимальным и
минимальным числом, представленными длиной разрядной сетки - количества
позиций в записи числа.

Для перевода чисел из одной системы счисления в другую в общем случае


можно использовать последовательное деление числа на основание системы
счисления и запись остатков. В качестве примера приведем перевод числа
100010102 = 13810 в девятичную систему счисления.

100010102 | 112 = 39 (138/9=15, остаток 3)


000011112 | 1102 = 69 (15/9=1, остаток 6)
000000012 | 12 = 19 (1/9=0, остаток 1)

100010102 = 1639 = 13810.

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

20=19 21=29 22=49 23=89


24=179 25=359 26=719 27=1529

1•27+0•26+0•25+0•24+1•23+0•22+1•21+0•20=1529+89+19=1639

3
Как правило, этот метод используется для операций с двоичной системой
счисления, так как вычислительные устройства реализуют именно систему
счисления с основанием 2.

Шестнадцатеричная и восьмеричная системы счисления используются для


сокращения длины записей двоичных чисел. В восьмеричной системе счисления
используются цифры от 0 до 7, в шестнадцатеричной используются цифры от 0
до 9 и символы A,B,C,D,E,F для обозначения чисел от 10 до 15 соответственно.

Так как основания этих систем являются степенями 2, то перевод чисел между
двумя системами прост. Знаки группируются по 4(3) для шестнадцатеричной
(восьмеричной) системы счисления, начиная с младшего разряда, и для каждой
группы записывается соответствующий ей знак.

111 010 101 = 7258


1 1101 0101 = 1D516

Помимо используемой системы счисления, представление информации зависит


от кодирования числа. Чаще всего числа представляются в двоичном коде, при
этом значение числа определяется полиномом xn-1•2n-1+…+x1•21+x0•20,
а диапазон разрядной сетки равен [0.. 2n-1].

Так представляются числа без знака в большинстве цифровых систем, в том


числе в процессорах.

Примеры других кодов и области их применения будут рассмотрены в разделе


1.3.

1.2. Представление чисел со знаком.

Для представления чисел со знаком используется несколько различных методов


кодирования, однако, как правило, один разряд отводится для размещения
информации о знаке и называется знаковым разрядом. Таким образом,
максимальное положительное число, которое можно записать с использованием
n битов при представлении чисел со знаком, равно 2n-1.

Для представления двоичных чисел со знаком используется несколько кодов:


1. Прямой код
Под знак отводится старший разряд числа, если он равен 0 - число
положительное, 1 - отрицательное. Данное представление неудобно при
выполнении арифметических операций, так как операции сложения и
вычитания работают неправильно для чисел со знаком. Кроме того, имеются
два нуля - "положительный" (0000) и "отрицательный"(1000).

При таком представлении значение числа "xn-1,xn-2,..,x0" определяется как


(-1)Xn-1•(xn-2•2n-2+…+x1•21+x0•20).
Диапазон разрядной сетки - [-2n-1+1.. 2n-1-1].

4
2. Обратный код (с дополнением до 1)
Обратный код получается инверсией всех разрядов числа, причем у
положительных чисел знаковый разряд имеет значение 0. Недостатком
данного способа кодирования также является наличие двух нулей. Код
называется кодом с дополнением до 1, так как дополнением называется
дополнение числа до ближайшей следующей более высокой степени 2,
расположенной за пределами разрядной сетки. В случае 4-разрядного числа
это 24=16. Таким образом, инвертируя число, получаем, что полное
дополнение равно поразрядному дополнению плюс 1.
4=0100; 11=1011; 15-4=11=1111

При таком представлении значение числа "xn-1,xn-2,..,x0" определяется как


-xn-1•(qn-1-1)+xn-2•qn-2+…+x1•q1+x0•q0.
Диапазон разрядной сетки - [-2n-1+1.. 2n-1-1].

3. Дополнительный код (с дополнением до 2)


Наиболее широко используется дополнительный код. Арифметико-
логические устройства существующих микропроцессоров и
микроконтроллеров используют, как правило, дополнительный код.
Дополнительный код формируется прибавлением единицы к записи числа в
обратном коде. Код называется кодом с дополнением до 2-х, так как
прибавляется еще одна единица, сокращающая расстояние дополнения.
Достоинствами такого представления отрицательных чисел является
легкость реализации вычислительных устройств и то, что в коде имеется
только один ноль. Так как осуществляется прибавление 1, то диапазон
чисел, которые могут быть представлены n-разрядным двоичным числом,
равен -2n…2n-1. Например, байт (8-разрядное число) при беззнаковом
представлении кодирует значения [0..255], в знаковом в дополнительном
коде - [-128..127].

При таком представлении значение числа "xn-1,xn-2,..,x0" определяется как


-xn-1•qn-1+xn-2•qn-2+…+x1•q1+x0•q0.
Диапазон разрядной сетки - [-2n-1.. 2n-1-1].

Представим число -4 в дополнительном коде и 12 без знака. Для


представления обоих чисел достаточно 4 разрядов: -410 = 11002 и 1210=11002
Обратите внимание - из представления чисел -4 и 12 видно, почему данный
код называется дополнительным. Число и дополнение его модуля (разность
модуля системы счисления и числа) в сумме равны основанию системы
счисления. -4 = 11002, 4=01002 4=12=11002, 12+4=16=100002.

4. Смещенный код (код со смещением)


Для определения значения из числа, представленного в коде без знака,
вычитается смещение (чаще всего это число 2n-1 или 2n-1-1). Значение ноль в
смещенном коде двоичном коде смещено к значению наименьшего числа в
диапазоне разрядной сетки. В случае, если смещение равно 2n-1, код
соответствует дополнительному коду, в котором значение знакового разряда
1 соответствует положительным, а 0 - отрицательным числам. Примеры
использования кода: представление показателя в числах с плавающей
запятой, представление данных в АЦП и ЦАП при работе с биполярным
входом.

5
При таком представлении значение числа "xn-1,xn-2,..,x0" определяется как
xn-1•qn-1+xn-2•qn-2+…+x1•q1+x0•q0 - k, где k - смещение.
Диапазон разрядной сетки - [-k.. 2n-1-1-k].

Таблица 1. Запись чисел со знаком в различных кодах

Прямой Обратный Дополнительный Смещенный


+7 0111 0111 0111 1111
+6 0110 0110 0110 1110
+5 0101 0101 0101 1101
+4 0100 0100 0100 1100
+3 0011 0011 0011 1011
+2 0010 0010 0010 1010
+1 0001 0001 0001 1001
+0 0000 0000 0000 1000
-0 1000 1111 нет нет
-1 1001 1110 1111 0111
-2 1010 1101 1110 0110
-3 1011 1100 1101 0101
-4 1100 1011 1100 0100
-5 1101 1010 1011 0011
-6 1110 1001 1010 0010
-7 1111 1000 1001 0001
-8 нет нет 1000 0000

Обратите внимание - во всех представленных кодах знак числа определяется


старшим разрядом!

1.3. Прочие коды

Другие коды могут использоваться другие способы кодирования, например, для


более удобного представления чисел или улучшения характеристик аппаратуры.
Приведем в качестве примера двоично-десятичный код и код Грея. Более
подробное рассмотрение прочих кодов дано в [1].

1.3.1. Двоично-десятичный код

Двоично-десятичный код, удобно использовать при выводе чисел на


семисегментные индикаторы. В англоязычной литературе используется термин
BCD (Binary-Coded Decimals). В этом коде на кодирование каждой десятичной
цифры отводится 4 двоичных разряда. Таким образом, удобно осуществлять
потетрадное извлечение десятичных знаков и вывод их на индикатор.
Представление, в котором в байте используются обе тетрады, называется
упакованным, а если в байте хранится одно десятичное число в младшей
тетраде - неупакованным.

8210 = 1000 0010 (уп.) = 0000 1000 0000 0010 (неуп.)

В ряде микропроцессоров имеются специальные команды выполнения двоично-


десятичной коррекции для сложения и вычитания. В большинстве случаев
данная задача встает при использовании микроконтроллеров и для чисел,

6
больших разрядности контроллера, поэтому часто применяется формирование
кода путем последовательных вычитаний степеней 10.

Пример: Формируем неупакованное двоично-десятичное число из 16-


разрядного на 8-разрядном контроллере с операцией деления.

#define cDigits 5
int static DDCSub[cDigits] = {100,1000,10000};
void bin2ddc(int val, short int* digs)
{
int i,j,temp;
for (i=cDigits-1;i>1;i--)
{
j=0;
while((temp=val-DDCSub[i-2])>0)
{
val=temp;
j++;
}
digs[i]=j;
}
digs[1]=val/10;
digs[0]=val%10;
}

Непосредственно с BCD кодом связан 7(8)-ми сегментный код для цифровой


индикации. Перевод существляется с помощью
 специального декодера в аппаратной реализации
a
 таблицы перекодировки в программной реализации
f b
Например, для вывода числа 5 требуется засветить светодиоды g
b,d,e,g,h (рис.1). Допустим, что a соответствует младшему разряду в
выводимом байте, а h - старшему и засветка осуществляется e
d
c

выводом "1". Тогда требуется вывести число 011011012. e h

Рис.1

Также используется модификация ДДК - код со смещением 3. Аналогичен ДДК,


c добавлением 3:
235 = 0010 0011 0101 - ДДК
= 0101 0110 1000 - со смещением 3.

Пример:
Диапазоны представления чисел:
а) в 8-разрядном упакованном двоично-десятичном коде: [0..99].
б) в 8-разрядном дополнительном коде: [-128..+127].
в) 32-х разрядным числом без знака: [0..232-1], при представлении чисел со
знаком в дополнительном коде: [-231 до 231-1].

7
1.3.2. Код Грея.

При применении этого кода при последовательном переходе от одного значения


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

0 0 0 0 0
1 0 0 0 1
2 0 0 1 1
3 0 0 1 0
4 0 1 1 0
5 0 1 1 1
6 0 1 0 1
7 0 1 0 0
8 1 1 0 0
9 1 1 0 1
10 1 1 1 1
11 1 1 1 0
12 1 0 1 0
13 1 0 1 1
14 1 0 0 1
15 1 0 0 0

Правило формирования - взять самый младший разряд, приводящий к


образованию нового состояния и инвертировать его.

Также код Грея может формироваться из двоичного кода числа. Правило


формирования разряда кода Грея следующее

K Гm  K m  K m1 ,

Где

K Гm - разряд кода Грея в позиции m;


K m - разряд двоичного кода без знака в позиции m (Km+1=0);

Обратное преобразование кода Грея в двоичный код требует больших затрат,


так как разряды двоичного числа вычисляются последовательно со старших
разрядов:

K m  K mГ  K m 1

Еще одно применение кода Грея - формирование базисных функций в таких


ортогональных преобразованиях, как преобразования Уолша и Адамара. Эти
преобразования широко используются в обработке данных и изображений.

8
Представление в коде Грея можно рассматривать как представление в
непозиционной системе счисления.

1.4. Сложение и вычитание чисел без знака и в дополнительном коде

Сложение и вычитание выполняется аналогично сложению и вычитанию в


десятичной системе счисления.

01001000 - переносы
00110100
00100101
+ --------
01011010

00011110 - заемы
00110100
00100101
- --------
00001111

Сложение/вычитание чисел в дополнительном коде и в представлении без знака


приводит к одинаковой последовательности двоичных разрядов. Представим
число -4 в дополнительном коде и 12 без знака. Для представления обоих чисел
достаточно 4 разрядов: -410 = 11002 и 1210=11002

210+1210=210 = 00102+11002 = 11102=1410


210+(-410)=11102+11002=11102 -210

Этот результат объясняет, почему дополнительный код используется в


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

1.4.1. Переполнение

Переполнением называется получение в результате арифметической операции


результата, который непредставим в данной разрядной сетке (числом данной
разрядности).

Результат при сложении и вычитании чисел может требовать на один двоичный


разряд больше, при выполнении умножения - удвоенное количество разрядов.
Рассмотрим, например, представление числа 15 без знака: 1510=11112
11112+11112=111102=3010 - 5 разрядов
11112*11112=111000012=22510 - 8 разрядов

Если данных разрядность ограничена, например, разрядностью процессора или


используемого типа данных, то дополнительный разряд, который потребовался
в примере сложения выше, записать некуда и происходит переполнение.
11112+11112=111102=1410 - 4 разряда и перенос, который не поместился в
разрядной сетке.

9
Таким образом, при сложении(вычитании) чисел без знака переполнение
определяется по наличию переноса(заема) из старшего разряда.

Однако при выполнении операций сложения и вычитания над числами в


дополнительном коде перенос(заем) в старшем разряде может появляться в
случаях, когда переполнения нет.

Очевидно, -2+(-4)=-6, и при сложении чисел появляется перенос (отмечен


серым), однако это не свидетельствует о переполнении:
11002+11102=1 10102.

В то же время результат сложения -6+-6=-12 не умещается в разрядную сетку, и


об этом свидетельствует смена знака числа:
10102+10102=1 01002.

Для детектирования переполнения при операциях над числами в


дополнительном коде требуется другой признак. Переполнение происходит,
если результат сложения двух чисел с одинаковым знаком или результат
вычитания чисел с противоположными знаками выйдет за пределы допустимого
диапазона, то есть, в первом случае сменит знак, а во втором если будет
повторять знак вычитаемого числа. Естественно, при сложении чисел с
различными знаками или вычитании чисел с одинаковым знаком в
дополнительном коде переполнения произойти не может.

Однако, детектирование переполнения при выполнении сложения и вычитания


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

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

Для сохранения переноса (заема) из старшего разряда в микропроцессорах


имеется специальный однобитный регистр, называемый флагом переноса. Он
может использоваться для определения факта переполнения или результат
сравнения чисел. Если Вы используете в коде на языке высого уровня
беззнаковый тип, например, unsigned int в C, то при сравнении чисел будет
анализироваться флаг переноса.

Для детектирования переполнения при операциях над числами в


дополнительном коде требуется другой флаг. Как правило, он называется
флагом переполнения. Значение флага переполнения имеет смысл только тогда,
когда операция осуществляется над числами в дополнительном коде. Если Вы
используете в коде на языке высого уровня знаковый тип, например, signed int в
C, то при сравнении чисел в машинном коде будет анализироваться флаг
переполнения.

10
Пример:

Определения флагов переноса и переполнения арифметико-логического


устройства (АЛУ) в процессорах 80x86:

CF(carry flag) - флаг переноса. Равен 1, если произошел перенос единицы при
сложении или заем единицы при вычитании. В противном случае равен нулю.
Кроме того, служит приемником для бита, который был сдвинут из регистра
или ячейки памяти при выполнении операции сдвига.
OF (overflow flag) - флаг переполнения. Служит индикатором ошибки при
операциях над числами со знаком. OF = 1, если результат сложения двух чисел с
одинаковым знаком или результат вычитания чисел с противоположными
знаками выйдет за пределы допустимого диапазона, то есть, в первом случае
сменит знак, а во втором если будет повторять знак вычитаемого числа.

1.4.2. Сложение и вычитание чисел большой разрядности

Разрядность АЛУ микропроцессора фиксирована. Используемые в настоящее


время микропроцессоры и микроконтроллеры выполняют операции над
данными шириной от 8 до 64 бит. Например, современные микроконтроллеры
обычно имеют разрядность 8 или 32, процессоры общего назначения - 64 бита.
Однако, часто требуется реализовать работу с арифметикой большей
разрядности.

Допустим, у нас имеется 8-разрядный микроконтроллер. Требуется сложить или


вычесть два 16-разрядных числа (далее со знаком/без знака будем опускать, где
это не требуется, так как мы убедились, что при сложении и вычитании
значения результата от этого не зависят, а зависит только их толкование).

В микропроцессорах есть команды сложения и сложения с учетом переноса.


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

00110100 10100110
00100101 11010101
+ --------------------
01011010 «1 01111011

00110100 10100110
00100101 11010101
- --------------------
00001110 »1 11010001

В первом случае произошел перенос из младшего байта, во втором - заем в


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

11
1.4.3. Расширение разрядности

При выполнении арифметических операций часто требуется сменить


разрядность числа. Для уменьшения разрядности с сохранением значения числа
требуется отбросить необходимое количество старших разрядов. Однако
следует убедиться, что значение числа может быть представлено в новой
разрядной сетке. Например, для представления числа 25610=1000000002
требуется не менее 9 разрядов.

При работе с числами без знака для увеличения разрядности следует добавить
необходимое количество нулевых старших разрядов.

При работе с числами со знаком в дополнительном коде следует произвести


знаковое расширение - скопировать в добавляемые разряды значение старшего
разряда исходного числа.

Действительно, пусть число представлено в дополнительном коде n разрядами:


-xn-1•2n-1+xn-2•2n-2+…+x1•21+x0•20,
произведем знаковое расширение до n+1 разрядов:
-xn•2n+xn-1•2n-1+xn-2•2n-2+…+x1•21+x0•20.
Для того, чтобы числа были равны, подчеркнутые части должны быть равны:
-xn•2n+xn-1•2n-1=-xn-1•2n-1
Очевидно,
-xn•2n=-xn-1•2n-1•2
и тогда
-xn=-xn-1.

То есть, для сохранения значения числа в добавляемый знаковый разряд


необходимо записать знаковый разряд исходного числа. Итеративно следует,
что при расширении на большее количество разрядов следует записать
знаковый разряд исходного числа во все добавляемые разряды.

Пример:
Представим число -12 8-ми разрядным и 16-разрядным словами:
-12=1111 01002=F416
-12=1111 1111 1111 01002=FFF416

2. Представление чисел с дробной частью


2.1. Представление чисел с фиксированной запятой
Любое конечное число можно записать (приближенно) полиномом в десятичной
системе счисления.

Например, 12.06 = 1•101+2•100+0•10-1+6•10-2

Аналогично, переходя к двоичной системе счисления, можно зафиксировать


запятую в любой позиции и получить возможность представлять числа с
дробной частью.

12
Тогда значение числа без знака разрядностью n с дробной частью длиной k
разрядов будет определяться полиномом:
an-k-1•2n-k-1+...+ a0•20+ a-1•2-1+…+a-k•2-k
Диапазон разрядной сетки для такого формата:
[0..+2n-k-2-k]

Значение числа в дополнительном коде будет определяться полиномом:


-an-k-1•2n-k-1+...+ a0•20+ a-1•2-1+…+a-k•2-k
Диапазон разрядной сетки для такого формата:
[-2n-k-1..+2n-k-1-2-k]

Например, зафиксируем запятую во второй позиции и рассмотрим следующую


последовательность двоичных разрядов и ее значение:
110.112 = 1•22+1•21+0•20+1•2-1+1•2-2 = 6.75
Та же последовательность в дополнительном коде:
110.112 = -1•22+1•21+0•20+1•2-1+1•2-2 = -1.25

Следует понимать, что положение фиксированной запятой не влияет на


значения разрядов результата выполнения таких базовых арифметических
операций, как сложение, вычитание и умножение. Каждой позиции в
позиционной системе счисления сопоставлен вес, так что мы можем
рассматривать приведенные числа, как целые: 110112 = 2710 в коде без знака и -
510 в доп. коде. Таким образом, все алгоритмы арифметических операций над
целыми числами применимы к числам с фиксированной запятой.

Часто формат с фиксированной запятой обозначается как m.k, например, 2.30


или 1.15. В этом случае первое число означает количество символов в целой, а
второе – в дробной части.

Например, в процессорах цифровой обработки сигналов распространен 16-ти


разрядный формат 1.15, в котором используется представление в
дополнительном коде, при котором запятая фиксирована после старшего,
знакового разряда. При этом минимальное число, представимое в данной
разрядной сетке, равно -1 (1.0000000000000002), а максимальное
приблизительно равно +0.99997 (0.1111111111111112). Это удобно при
умножении чисел, так как умножение двух чисел, принадлежащих диапазону
[-1..1) дает результат в том же диапазоне. Это исключает необходимость
расширения разрядной сетки при умножении.

При сложении двух чисел запятая остается фиксированной в той же позиции,


при умножении количество целых и дробных разрядов удваивается. Например,
при умножении двух 16-ти разрядных чисел в формате 1.15 мы получаем 32-х
разрядный результат в формате 2.30. Это не противоречит замечанию об
отсутствии необходимости расширения разрядной сетки, данному в
предыдущем абзаце, так как один старший и пятнадцать младших разрядов
могут быть отброшены и мы получим правильный результат без переполнения
(возможно, с потерей точности при отбрасывании младших разрядов).

В микроконтроллерах, не поддерживающих операции над числами с дробной


частью, можно эмулировать их, используя операции над целыми числами.
Например, для повышения точности при расчетах данные можно сдвинуть на

13
несколько разрядов, например, сдвиг данных влево на три разряда и
использование таких данных в расчетах сопоставляет младшему разряду вес 1/8.

Для перевода десятичного числа с фиксированной запятой в двоичное


представление m.k удобно умножить десятичное значение на 2k, после чего
округлить полученное число до целого и перевести его в двоичное
представление.

Пример:
A = 13.241 представить в формате 5.11
13.241*211=27117,568≈27118
2711810 = 01101.00111101110
машинное изображение числа Aм=01101.00111101110
Проведем проверку:
23+22+20+2-3+2-4+2-5+2-6+2-8+2-9+2-10 = 13.2412109375.
Абсолютная погрешность представления [A] равна
[A] = |A-Aм|= 0,0002109375
Относительная погрешность представления [A] равна
[A]= [A]/|Aм| = 1.593*10-5

Очевидно, при таком переводе числа из одной системы счисления в другую


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

2.2. Представление чисел с плавающей запятой


При использовании десятичной системы счисления числа с плавающей запятой
записываются в виде m•10e, где m-мантисса, а e – экспонента (показатель).
Естественно, может быть использована запись с любым другим основанием a.
Число называется нормализованным, если мантисса лежит в диапазоне (1,1/a].
Например, при a=10, 1.23•1023 и 0.0123•1025 ненормализованные представления,
0.123•1024 - нормализованное представление

При операциях с числами с плавающей запятой осуществляются отдельные


операции над мантиссой и экспонентой.

При сложении и вычитании осуществляется уравнивание экспонент. Число, у


которого экспонента меньше, корректируется сдвигом мантиссы (сдвиг на одну
позицию вправо соответствует увеличению экспоненты на 1, влево -
уменьшению на 1), и если после этой операции мантисса не равна нулю,
осуществляется сложение (вычитание) мантисс. После этого проводится
нормализация.

При умножении чисел экспоненты складываются, а мантиссы перемножаются.


При делении экспоненты вычитаются, а мантиссы делятся. После получения
результата осуществляется его нормализация.

Для представления двоичных чисел с плавающей запятой в настоящее время


стандартным в практических приложениях является формат IEEE-754.
Существует несколько стандартных вариантов представления чисел со знаком -
4,8 и 10-байтное.

14
Формат представления числа с плавающей запятой в формате IEEE описывается
следующим образом:

ст. разряд мл.разряд


s e m

где
s - знаковый разряд.
Равен 0, если число положительное, и 1, если число отрицательное. Длина поля
- 1 разряд.

m - мантисса.
Содержит мантиссу без знака с запятой, фиксированной после старшего
разряда, то есть значение определяется как
m= a0•20+ a-1•2-1+…+a-n•2-n,
где n - длина мантиссы.
При этом старший бит a0 в числе не хранится (скрытый бит). Его значение
определяется значением показателя (см. ниже).

e- экспонента (показатель).
Содержит значение показателя, представленное в коде со смещением
2n/2-1,
где n - длина показателя.

Длина полей в различных форматах:


длина числа m – мантисса e – экспонента Название
4 байта 23 8 single
8 байт 52 11 double

Также определено два формата, зависящих от реализации. Эти форматы могут


использоваться для повышения точности при промежуточных вычислениях.
>=43 бит >=32 бит >=11 бит single extended
>=79 бит >=64 бит >=15 бит double extended

В стандарте учитывается возможность возникновения при вычислениях таких


значений, как бесконечность и неопределенность (NaN). Для представления
таких значений используются специальные значения битовых полей.
NaN – специальное значение ”не число”, соответствующее результату
арифметической операции, значение которой не может быть определено.
Например, NaN возвращается при попытке сложения +∞ и -∞, деления 0 на 0,
взятия логарифма отрицательного числа, операции над другим числом со
значением NaN и т.д..

Различается два вида NaN - quiet (тихий) и signaling (сигнализирующий).


Получение сигнализирующего NaN в процессе вычислений обычно вызывает
исключение. Тихий NaN не порождает исключений, а распространяется при
вычислениях, порождая результат NaN. Это может быть использовано для
оптимизации вычислений. Иногда проще и более вычислительно эффективно
получить результат со значением NaN и понять, что, к примеру, при

15
вычислении определителя матрицы что-то пошло не так, чем прерывать процесс
вычисления обработкой исключения процессором.

Настройку обработки NaN необходимо уточнять для конкретного процессора,


языка программирования, компилятора и используемых библиотек.

Значение числа с плавающей запятой v в формате single определяется


следующим образом:
1. Если e = 255 и m != 0, то для любого s: v = тихий NaN, если старший бит
m = 1, v = сигнализирующий NaN, если старший бит m = 0
2. Если e = 255 и m = 0 , то v = -∞, если s = 1 и v = +∞, если s = 0
3. Если 0 < e < 255 , то v = (-1)s 2 e-127 (1,m)2
4. Если e = 0 и m != 0 , то v = (-1)s 2 -126 (0,m)2
5. Если e = 0 и m = 0 , то v = -0, если s = 1 и v = +0, если s = 0
Значение числа с плавающей запятой v в формате double определяется
следующим образом:
1. Если e = 2047 и m != 0, то для любого s: v = тихий NaN, если старший бит
m = 1, v = сигнализирующий NaN, если старший бит m = 0
2. Если e = 2047 и m = 0 , то v = -∞, если s = 1 и v = +∞, если s = 0
3. Если 0 < e < 2047 , то v = (-1)s 2 e-1023 (1,m)2
4. Если e = 0 и m != 0 , то v = (-1) s 2 -1022 (0,m)2
5. Если e = 0 и m = 0 , то v = -0, если s = 1 и v = +0, если s = 0

Число, представленное в п.3, называется нормализованным. Это основной


формат представления числа в стандарте IEEE-745. Мантисса
нормализованного числа лежит в диапазоне [1..2). При этом запись (1,m)2
означает двоичное число, образованное полем мантиссы в дробной части и 1 в
целой части. 1 не хранится в числе, таким образом, несмотря на то, что в
стандарте указано, что длина мантиссы в формате single равна 24, в числе
хранятся только 23 бита дробной части.

В случае, если при вычислениях показатель становится равным нулю, число


перестает быть нормализованным (п. 4). Числа, представленные в этом формате,
называются субнормальными. Обратите внимание, что значение показателя
равно значению показателя при e=1. Однако, скрытый бит становится равным 0,
а число может уменьшаться и дальше, при этом все больше старших разрядов
мантиссы будут принимать значение 0. Таким образом обеспечивается
равномерное распределение значений на числовой оси в окрестности нуля. На
рис.2 красным отмечены позиции на числовой оси, соответствующие
субнормальным числам.

0,000..01*2-126 1,000..10*2-126 1,000..10*2-125


-0,000..01*2-126 1,000..01*2-126 1,000..01*2-125
1,000..00*2-126 1,000..00*2-125
0,111..11*2-126 1,111..11*2-126

Рис. 2. Значения малых чисел с плавающей запятой на числовой оси

16
Также обратите внимание на то, что при увеличении показателя на 1 расстояние
между позициями на числовой оси удваивается.

Примеры чисел в формате IEEE-754 (серым выделен показатель):


1 = 1.0•20 = 0011 1111 1000 0000 0000 0000 0000 00002
0
1.75 = (1.0+0.5+0.25)•2 = 0011 1111 1110 0000 0000 0000 0000 00002
-2 =1.0•21 = 1100 0000 0000 0000 0000 0000 0000 00002

но особый случай нормализации для малого числа:


3e-39  0.25•2-126= 0000 0000 0010 0000 0000 0000 0000 00002
и запись нуля:
+0 = 0000 0000 0000 0000 0000 0000 0000 00002
-0 = 1000 0000 0000 0000 0000 0000 0000 00002

3. Умножение двоичных чисел


В данном разделе будут рассмотрены различные алгоритмы умножения
двоичных чисел.

3.1. Сдвиги

Для реализации умножителей необходимо ввести понятие операций сдвига.


Рассмотрим различные операции сдвига и их влияние на значение
представляемого числа.

Сдвиг влево означает увеличение веса каждого разряда на 1, вправо -


уменьшение. При выполнении логического сдвига как влево, так и вправо,
новые разряды заполняются нулями. При арифметическом сдвиге вправо
осуществляется расширение знака (см. 1.4.3.). Арифметический и логический
сдвиг влево выполнятся одинаково.

Сдвиг числа на один разряд соответствует его умножению/делению на


основание системы счисления. Это широко используется при обработке
двоичных данных, так как на большинстве количестве процессоров операция
сдвига выполняется быстрее, чем операция умножения. Поэтому умножение на
2 зачастую предпочтительнее заменять операцией сдвига на один разряд влево.
На языках высокого уровня не рекомендуется это делать в коде, так как это
ухудшает читаемость кода, а оптимизирующий компилятор вполне может
сделать это самостоятельно.

В языках описания аппаратного состава, напротив, лучше вместо умножения и


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

В системах команд процессоров имеются также другие операции сдвига -


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

17
логический сдвиг вправо
0   С

арифметический сдвиг вправо


  С

логический и арифметический сдвиг влево


С   0

циклический сдвиг влево


С  

циклический сдвиг вправо


  С

циклический сдвиг влево через перенос


 С  

циклический сдвиг вправо через перенос


  С 

3.2. Умножение ”столбиком”

Операция умножения двоичных чисел без знака может осуществляться


аналогично умножению десятичных чисел - столбиком.

Пример:

1310=11012; 1010=10102; 1310*1010=13010=100000102

1101
1010
----
0000
1101
0000
1101
--------
10000010

Однако в программных и аппаратных реализациях умножения, как правило,


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

Рассмотрим алгоритм умножения, который может применяться, например, при


разработке программного обеспечения для микроконтроллеров, не имеющих
аппаратного умножителя [2].

18
Рассмотрим умножение на примере:
M= 6 = 01102, B= 5 = 01012.

Перед началом умножения обнуляется аккумулятор C.


Цикл умножения состоит из следующих операций:
1. Если младший бит B не равен 0, произвести прибавление множимого M к
аккумулятору
2. Сдвинуть аккумулятор C и множитель B на один разряд вправо.
Цикл повторяется столько раз, сколько разрядов во множителе B.

При этом старший бит в сомножителях равен нулю во избежание переполнения


при сложении чисел. Сдвиги производятся без знакового расширения.

M C B

0110 = 610 0000 0000 0101 = 510


+ 0110
0110 0000
сдвиг

0110 0011 0000 0010


+ 0000
0011 0000
сдвиг

0110 0001 1000 0001


+ 0110
0111 1000
сдвиг

0110 0011 1100 0000


+ 0000
0011 1100
сдвиг

0001 1110 = 3010

При умножении чисел со знаком данный алгоритм неприменим.

Для реализации умножения чисел со знаком возможно внесение коррекций в


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

Перед началом умножения обнуляется аккумулятор C.


Цикл умножения состоит из следующих операций:
1. Если младший бит B не равен 0, произвести прибавление множимого M к
аккумулятору.
2. Сдвинуть аккумулятор C и множитель B на один разряд вправо. Если
осуществлялось сложение на предыдущем этапе, перенос от предыдущего
сложения занести в освобождающийся разряд, иначе произвести
арифметический сдвиг.

19
Цикл повторяется N-1 раз, где N – число разрядов во множителе B.
В завершение обрабатывается старший разряд множителя B. Если старший
разряд множителя не равен 0 (множитель – отрицательное число), из значения в
аккумуляторе вычитается множимое M.

При необходимости минимизации объема кода и сохранения возможности


умножать числа со знаком и без знака возможно использование другого
подхода, использующего умножение "столбиком" чисел без знака:
1. Определить и сохранить знак результата.
2. Преобразовать сомножители к модулю
3. Произвести умножение
4. При необходимости поменять знак результата

3.3. Умножение чисел большой разрядности

Выбор алгоритма всегда связан с аппаратурой, которая будет реализовывать


данную операцию. В большинстве современных микроконтроллеров и
процессоров есть аппаратные умножители и Вам вряд ли придется
реализовывать умножение с помощью сдвигов и сложений, рассмотренное
выше. Однако может возникнуть необходимость умножения чисел разрядности
большей, чем разрядность умножителя в процессоре. Например, при наличии в
системе команд 8-ми разрядного контроллера операции умножения двух 8-ми
разрядных чисел с 16-ти разрядным результатом, можно осуществить
умножение 16-ти разрядных чисел следующим образом:

Пусть
A=aст*256+aмл
B=bст*256+bмл

Где aст – значение числа, представленного 8 старшими разрядами множителя A


aмл – значение числа, представленного 8 младшими разрядами множителя A,
также аналогично множитель B.

A*B= aст*bст*65536+aмл*bст*256+bмл*aст*256+ aмл* bмл.


A*B= (aст*bст)<<16+(aмл*bст)<<8+(bмл*aст)<<8+ aмл* bмл.

То есть, операция умножения реализуется с помощью операций умножения,


сдвига и сложения.

Вообще, в основе многих операций над числами большой разрядности (деление,


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

Для таких задач полезно знать формулу, позволяющую сократить количество


умножений и известную как формула Карацубы.

Пусть дано два слова A и B одинаковой разрядности N, причем N-четное.


Разделим каждое слово на две половины длиной N/2. Тогда
A=a1*R+a0
B=b1*R+b0,

20
где R равно основанию системы счисления в степени N/2.

Тогда вычисление произведения по формуле


A*B= a1*b1*R2+(a0*b1+b0*a1)*R+ a0* b0.
можно заменить формулой
A*B= a1*b1*R2+((a1-a0)*(b0-b1)+a1*b1+b0*a0)*R+ a0* b0,
требующей всего три умножения
u1=a1*b1;
u2=a0*b0;
u3=(a1-a0)*(b1-b0).

Далее каждое умножение может раскладываться аналогично вплоть до


разрядности, аппаратно поддерживаемой процессором.

При применении этого метода количество умножений является величиной


порядка
N log2 3  N 1.585 ,

в то время как для обычного умножения


N log2 4  N 2 .

Однако, при применении такого метода возрастает количество операций


сложения и вычитания и применение этого метода имеет смысл в тех случаях,
когда операция умножения требует больше времени, чем операции сложения и
вычитания.

Для умножения особо длинных чисел может использоваться алгоритм Тоома-


Кука, в котором осуществляется разбиение числа на большее число частей
(алгоритм Карацубы выводится как частный случай умножения Тоома-Кука для
разбиения числа на две части). Также существует метод Шёнхаге-Штрассена,
основанный на быстром преобразовании Фурье. Эти методы обычно
применяются для умножения чисел, содержащих тысячи и более десятичных
разрядов.

21
3.4. Умножение. Формирование частичных произведений.

При аппаратной реализации умножителя нет возможности использовать


операцию умножения. Рассмотрим более подробно умножение двух двоичных
чисел из раздела 3.2.

Пример:

M=1310=11012; B=1010=10102; C=1310*1010=13010=100000102

1101
1010
----
0000 S
1101
0000
1101
--------
10000010

Введем следующую терминологию:


M – множимое,
B – множитель,
С – результат,
S – частичные произведения.

В данной терминологии операцию умножения можно описать как


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

Очевидно, что для формирования одного частичного произведения может


использоваться любое число разрядов множителя. Для приведенного в разделе
3.3. примера реализации умножения 16-ти разрядных чисел c использованием
операции умножения 8-ми разрядных чисел можно считать, что одновременно
анализируется 8 разрядов множителя.

Рассмотрим более подробно логику формирования частичных произведений на


уровне вентилей для умножения чисел без знака.

В случае, если для формирования частичного произведения используется один


разряд множителя, логика формирования частичного произведения Si для
разряда bi может быть описана как

Si=M*bi, где bi{0,1}

При аппаратной реализации это потребует одного вентиля И на разряд (рис.3).

22
Рис. 3

В случае, если для формирования частичного произведения Si используется два


разряда множителя (bi,bi+1), логика формирования частичного произведения
может быть описана как

Si=M*(bi,bi+1), где (bi,bi+1){0,1,2,3}

Аппаратно такую логику можно реализовать как мультиплексор четырех


возможных частичных произведений:

Si=0 при (bi,bi+1)=0;


Si=M при (bi,bi+1)=1;
Si=2*M=M<<1 при (bi,bi+1)=2;
Si=3*M=2*M+M=(M<<1)+M при (bi,bi+1)=3.

Аппаратная реализация сдвига набора двоичных разрядов на фиксированное


число позиций достаточно проста (см. рис. 4), в то время как реализация сдвига
и сложения одновременно требует последовательной реализации сдвига и
сложения.

Рис. 4

23
Очевидно, что чем больше разрядов множителя анализируется одновременно,
тем больше ресурсов требует логика формирования частичного произведения.

Сложение полученных частичных произведений можно осуществить


пирамидальным деревом сумматоров, в котором на каждом уровне число
сумматоров сокращается вдвое. То есть, если имеется N частичных
произведений, на первом уровне N/2 сумматоров складывают их попарно. На
следующем уровне N/4 сумматоров складывают выходы сумматоров первого
уровня и т.д.. Очевидно, что при таком подходе для сложения требуется
ceil(log2N) уровней и до N-1 сумматоров.

Таким образом, при увеличении числа одновременно анализируемых разрядов


множителя усложняется логика формирования частичных произведений, но
уменьшается их количество, что упрощает схему их сложения. Следовательно,
для аппаратной реализации на конкретной платформе (в заданном базисе)
можно определить оптимальное количество разрядов множителя,
анализируемых одновременно, исходя из требуемого быстродействия и объема
используемых ресурсов.

Приведенные выше методы вычисления и сложения частичных произведений


имеют ряд недостатков. Например, при анализе двух и более разрядов
одновременно появляются ”неудобные” для вычисления частичные
произведения A*K, где K-не степень двойки (как уже было отмечено, если K-
степень двойки, то такое частичное произведение может быть вычислено как
A<<(log2K), что сравнительно просто реализуется аппаратно). Пирамидальное
дерево сумматоров также может быть заменено более эффективной с точки
зрения быстродействия реализацией сложения частичных произведений,
которая будет рассмотрена ниже.

Таким образом, при реализации умножителя можно выделить три задачи:


1. Упростить логику формирования частичных произведений
2. Уменьшить количество частичных произведений.
3. Повысить быстродействие логики сложения частичных произведений.

Наиболее распространенным подходом, позволяющим решить первые две


задачи, является алгоритм Бута (Booth). Для решения третьей задачи часто
используется т.н. дерево Уоллеса (Wallace tree).

3.5. Умножение. Алгоритм Бута.

Рассмотрим идеи, лежащие в основе алгоритма Бута.

Допустим, производится умножение 2*7.

0010
0111
--------
+ 0010
+ 0010
+ 0010
+0000
--------
00001110

24
Эту операцию можно преобразовать к виду 2*(8-1), то есть,

0010
0111
--------
- 0010
+ 0000
+ 0000
+0010
--------
00001110

Обобщая данный случай, любая подстрока множителя с непрерывной


последовательностью единиц вида xx011..11xx может быть преобразована к
виду xx100..00xx-xx000..01xx. При этом многократное сложение ненулевых
частичных произведений будет заменено вычитанием двух ненулевых
частичных произведений. Кроме того, каждое из этих частичных произведений
имеет вид A*2K и может быть сформировано как A<<K.

Однако, для реализации приведенного выше примера умножения в виде 2*(8-1)


требуется каким-то образом детектировать начало и конец последовательности
единиц. Например, для того, чтобы не формировать частичное произведение для
бита множителя, находящегося в середине последовательности единиц,
необходимо иметь информацию о содержимом соседних разрядов. А для
формирования частичного произведения, равного 2*(-1) надо знать, что именно
он находится в начале последовательности единиц (является младшим битом в
группе единичных битов множителя).

В модифицированном кодировании по Буту, лежащем в основе


рассматриваемого алгоритма, группы разрядов множителя анализируются ”с
перекрытием”.

Для рассматриваемого примера, анализируя разряды множителя попарно,


можно определить следующие комбинации:

Бит i Бит i-1 Описание Пример


0 0 Середина последовательности нулей 0001011000
0 1 Конец последовательности единиц 0001011000
1 0 Начало последовательности единиц 0001011000
1 1 Середина последовательности единиц 0001011000

Для каждой пары разрядов множителя можно определить правила


формирования частичного произведения.

00: Середина последовательности нулей - не выполняется никакой операции


(частичное произведение равно нулю)
01: Конец последовательности единиц, добавить множимое к промежуточному
результату (частичное произведение равно +множимое)
10: Начало последовательности единиц, вычесть множимое из промежуточного
результата (частичное произведение равно - множимое)
11: Середина последовательности единиц - не выполняется никакой
арифметической операции (частичное произведение равно нулю)

25
Для корректного анализа старшего и младшего разрядов числа вводятся
дополнительные разряды (на схеме отмечены серым в разрядах множителя B).

0010 A
001110 B
--------
-0000010 001110 -A
0000000 001110 0
0000000 001110 0
+0010000 001110 A
0000000 001110 0
--------
+0001110

Алгоритм Бута, кроме того, позволяет реализовать умножение чисел со знаком


в дополнительном коде. Представим множимое как
A=-an-1•2n-1+[i=0..n-2](ai•2i)
и множитель как
B=-bn-1•2n-1+[i=0..n-2](bi•2i).

bi bi-1 Част. произв. bi-1-bi Формирование


0 0 0 0 A*( bi-1-bi)
0 1 +A 1 A*( bi-1-bi)
1 0 -A -1 A*( bi-1-bi)
1 1 0 0 A*( bi-1-bi)

Таким образом, результат умножения равен cумме частичных произведений


вида:
(0-b0)*A+(b0-b1)*2*A+…+(bn-3-bn-2)*2n-3*A+(bn-2-bn-1)*2n-1*A =
{раскрывая скобки и вынося A за скобки} = A*B,
если на каждом этапе производить знаковое расширение частичного
произведения.

Рассмотренный алгоритм называется Бут-1. Бут-1 демонстрирует основные


идеи применения модифицированного кодирования по Буту, однако, редко
применяется на практике, так как формирование частичных произведений при
анализе одного разряда множителя достаточно просто и приводит к более
простой аппаратной реализации.

Алгоритм Бута можно развить для большего количества разрядов числа,


анализируемых одновременно. Перед рассмотрением алгоритма Бут-2 еще раз
рассмотрим обычный алгоритм, в котором разряды анализируются попарно без
перекрытия.

0010
0111
--------
+ 0110 0111
+ 1000 0111
--------
00001110

В данном случае первое частичное произведение равно множимое*3, где 3 -


значение младших двух разрядов множителя, второе частичное произведение

26
равно множимому. То есть, частичные произведения выбираются из набора
{0,+M,+2M,+3M}, где M - множимое. Как уже было отмечено выше,
формирование частичного произведения 3M аппаратно сложно.

Алгоритм Бут-2 позволяет избежать этого. 3M можно представить как 4M-M,


или, если учитывать, что следующее частичное произведение при записи
сдвигается относительно текущего на 2 разряда, как вычитание M в текущем
частичном произведении и прибавление M в следующем.

При анализе трех разрядов одновременно можно определить следующие


комбинации:

Бит i Бит i-1 Бит i-2 Описание Пример


0 0 0 Середина последовательности нулей 0001011100
0 0 1 Конец последовательности единиц 0001011100
0 1 0 Одиночная единица 0001011100
0 1 1 Начало последовательности нулей 0001011100
1 0 0 Начало последовательности единиц 0001011100
1 0 1 Одиночный ноль 0001011100
1 1 0 Конец последовательности нулей 0001011100
1 1 1 Середина последовательности единиц 0001011100

Для каждой комбинации разрядов множителя можно определить правила


формирования частичного произведения.

000: Середина последовательности нулей - не выполняется никакой операции


(частичное произведение равно нулю)
001: Конец последовательности единиц, добавить множимое к
промежуточному результату (частичное произведение равно +множимое)
010: Одиночная единица, добавить множимое к промежуточному результату
(частичное произведение равно +множимое)
011: Начало последовательности нулей - добавить множимое к промежуточному
результату с предварительным сдвигом на один разряд влево (частичное
произведение равно +2*множимое)
100: Начало последовательности единиц - вычесть множимое из
промежуточного результата с предварительным сдвигом на один разряд влево
(частичное произведение равно -2*множимое)
101: Одиночный ноль, вычесть множимое из промежуточного результата
(частичное произведение равно -множимое)
110: Конец последовательности нулей, вычесть множимое из промежуточного
результата (частичное произведение равно - множимое)
111: Середина последовательности единиц - не выполняется никакой
арифметической операции (частичное произведение равно нулю)

Например, рассмотрим последовательность битов множителя 00110 и


множимое M:

00110 формируется частичное произведение -M


00110 формируется частичное произведение +M, с учетом сдвига +M<<2

(+M<<2)-M=(+4*M)-M=+3M

27
В качестве примера работы алгоритма умножим два 8-разрядных числа:

-110*118=-12980

10010010
00011101100
------------------
-1111111100100100 00011101100
+1111110010010000 00011101100
-1111100100100000 00011101100
+1100100100000000 00011101100
0000000000000000 00011101100
------------------
+0000000011011100
+1111110010010000
+0000011011100000
+1100100100000000
------------------
+1100110101001100

Если в Бут-2 анализируется 3 разряда одновременно, то в Бут-3 - 4 разряда


одновременно. С ростом количества анализируемых одновременно разрядов
усложняется логика формирования частичных произведений. Начиная с Бут-3
неизбежно появляются частичные произведения, образованные умножением
множимого на число, не являющееся степенью двойки (например, в Бут-3
последовательность анализируемых бит множителя 0110 определяет частичное
произведение +3M), причем их количество быстро растет с ростом числа
анализируемых разрядов. По этой причине на практике редко используются
алгоритмы более сложные, чем Бут-3.

В [1] алгоритм, подобный рассмотренному, описан в разделе 5.7. "Ускорение


операции умножения. Анализ двух разрядов множителя одновременно".

3.6. Умножение. Дерево Уоллеса.

Структура, называемая деревом Уоллеса, позволяет избежать формирования


длинных цепей переноса, упростить и ускорить реализацию сложения в
аппаратных реализациях умножителей. Такое дерево состоит из нескольких
уровней, причем на каждом уровне параллельно складываются разряды,
находящиеся в одном “столбце” разрядов частичных сумм.

Рассмотрим в качестве примера умножение двух шестиразрядных чисел.

101011
011101
--------
+ 101011
+ 000000
+ 101011
+ 101011
+ 101011
+000000
--------
010011011111

28
Допустим, что для сложения частичных произведений используется
пирамидальное дерево сумматоров. Учитывая взаимные сдвиги частичных
произведений и необходимое расширение разрядности сумматоров на один
разряд для каждого сложения, отобразим процесс сложения частичных
произведений и получаемых частичных сумм:

101011
000000 00101011
101011
101011 10000001 01000101111
101011
000000 0101011 010011011111

Недостатком такой схемы сложения частичных произведений является большая


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

Для уменьшения задержки необходимо избежать возникновения длинных цепей


переносов. Для этого можно складывать не частичные произведения, а их
разряды в одном столбце. Например, можно использовать обычный модуль
сумматора. Ниже приведен пример сложения трех частичных произведений по
столбцам, выделены полученные разряды их суммы и переноса в следующий
разряд для одного из столбцов (рис. 5). Перенос в следующий разряд
записывается в позиции, соответствующей следующему старшему разряду, но
при этом к нему не прибавляется. Это позволяет избежать формирования цепей
переноса на промежуточных этапах сложения частичных произведений.

+ 101011 V
+ 000000 Y
+ 101011 Z

10000111 S
00101000 C

Рис. 5

Таким образом, с помощью сумматора можно “сжать” три разряда частичных


произведений в два разряда – один разряд суммы и разряд выходного переноса.
(т.н. сжатие 3:2).

Также на практике используются модули, осуществляющие сложение, или,


иначе, “сжатие” четырех входных операндов в один разряд суммы s и выходной

29
перенос c (т.н. сжатие 4:2, хотя на самом деле у модуля 5 входов и 3 выхода).
Обратите внимание на то, что промежуточный выходной перенос cout между
модулями не зависит от промежуточного входного cin и, таким образом, цепь
задержки от модуля, обрабатывающего младшие разряды, до модуля,
обрабатывающего старшие разряды, не возникает (рис. 6).

Рис. 6

Кроме того, можно реализовать схемы, осуществляющие сжатие большего


числа разрядов в несколько разрядов суммы и переноса. Ниже приведены
примеры схем, построенных на основе сумматоров и осуществляющих сжатие
(7:4) и (5:3) (Рис. 7).

Рис. 7

Рассмотрим, как с помощью сумматоров и схем 4:2 можно осуществить


сложение соответствующих разрядов частичных произведений.
 Будем использовать на первом этапе сжатие 3:2 (сумматоры).
 Каждый столбец разбивается на две группы по три разряда (верхнюю и
нижнюю), каждая из которых подается на сжимающий модуль.
 Для большей наглядности серым и малиновым помечены две группы
входных разрядов, каждая из которых подается на вход сжимающего
модуля и соответствующие им выходные разряды суммы и переноса и их
позиции на следующем этапе.

30
 Обратите внимание на то, что для уменьшения числа используемых
вентилей для младших и старших разрядов, в которых длина столбца
меньше 6, могут использоваться сжимающие модули с меньшим
количеством входов.
 Зеленым помечены разряды, которые переходят на следующий этап без
изменений и для которых, соответственно, не нужно задействовать
сжимающий модуль.

101011 a
000000 b => (s0,0,c0,0)
101011 d
101011 e
101011 f => (s0,1,c0,1)
000000 g

10000111 s0,0
010100 c0,0
01111101 s0,1
000001 c0,1

На втором этапе использование сжатия 3:2 неэффективно, так как длина


столбца в 4 разряда потребует 2-х сжимающих модулей. Будем использовать
сжатие 4:2.

10000111 s0,0
010100 c0,0
01111101 s0,1
000001 c0,1

01100011111 s1,0
01100011111 s1,0
001110000 c1,0

После того, как в процессе последовательных сокращений получаются два


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

001100011111 s1,0
0001110000 c1,0

010011011111

Приведенный пример показывает, что для любой разрядности множителя и


множимого может быть построено большое количество деревьев Уоллеса с
различными сжимающими схемами на разных этапах, однако, общими
особенностями всех схем, построенных по такому принципу, являются:
 Отсутствие цепочных переносов от младших разрядов к старшим;
 Приведение всех частичных произведений к двум числам, одно из
которых представляет сохраненные переносы, а другой - суммы для
последнего этапа дерева Уоллеса.

31
В настоящее время аппаратные умножители часто реализуются как умножители
Бута-Уоллеса, т.е. формирование частичных произведений осуществляется с
модифицированным алгоритмом Бута, а их сложение – деревом Уоллеса.

32
4. Деление двоичных чисел
4.1. Деление ”столбиком”

Деление двоичных чисел можно выполнять аналогично делению десятичных


чисел. Например, 1231/17 :

1231 |72
119
41
34
7

Кроме уменьшения числа арифметических операций, этот алгоритм позволяет


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

A B

0110 0010 1101| 45


- 0110 6*16 1)
1100 1101| -51
сдвиг

0110 1001 101|0 -51*2


+ 0110 6*16
1111 101|0 -6
сдвиг

0110 1111 01|00 -6*2


+ 0110 6*16
0101 01|00 84
сдвиг

0110 1010 1|001 84*2 2)


- 0110 6*16
0100 1|001 72
сдвиг

0110 1001 |0011 72*2


- 0110 6*16
0011 |0011 48
сдвиг

0011 |0111 Остаток=48/16=3 3)

Примечания.
1) В этом столбце условно записываем значение делителя, выровненного по
старшим битам делимого, это можно рассматривать как умножение на 2n
разрядов, где n - разрядность делителя, в данном случае - на 16.

33
2) Так как операции сложения и вычитания выполняются одинаково над
числами в дополнительном коде и числами без знака, такая трактовка значения
после сдвига допустима.
3) Было выполнено 4 сдвига делимого, что соответствует умножению на 16,
поэтому для получения реального значения просто считываем старшие 4
разряда из 8, что эквивалентно делению на 16.

Аналогично умножению, для упрощения выполнения операции деления можно


определить сначала знаки результата и остатка, произвести деление и
восстановить их знаки.

При делении знак результата может быть определен функцией "исключающее


ИЛИ" от знаков делимого и делителя, а знак остатка равен знаку делимого.

Следует отметить, что в отличие от алгоритма умножения, сложность алгоритма


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

С теоретической точки зрения значение двоичного числа определяется


полиномом, и, соответственно, деление и умножение двоичных чисел можно
сопоставить с делением и умножением полиномов. Из этой аналогии можно
получить ответ на вопрос, часто задаваемый про ускорение операции деления:
”Можно ли использовать операцию деления чисел меньшей разрядности для
ускорения деления чисел большей разрядности также, как это можно сделать
для умножения?”. Ответ – ”Нет, нельзя”.

4.2. Деление без восстановления остатка

При реализации алгоритма деления, рассмотренного выше, для каждого разряда


требуется сначала определить, является ли разница отрицательной или
неотрицательной, после чего определить значение разряда результата и
выполнить вычитание. Это неэффективно при программной реализации, так как
определение знака (или сравнение двух переменных) процессор выполняет,
выполняя вычитание, то есть, имеет место двойное увеличение объема
вычислений. Если не требуется получить значение остатка от деления, для
вычислений может быть использован метод без восстановления остатка [3].

На первом этапе этого алгоритма выполняется вычитание делителя из старших


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

Алгоритм предназначен для деления числа разрядности 2n на число разрядности


n. Число циклов равно n+1.

34
Вертикальной чертой отмечена граница между сдвигаемым последним разрядом
делимого и получаемым результатом.

Пусть, как и в прошлом примере, A = 6 = 01102, B = 45 = 0010 11012

A B

0110 0010 1101| 45


- 0110 6*16 1)
1100 1101| -51
сдвиг

0110 1001 101|0 -51*2


+ 0110 6*16
1111 101|0 -6
сдвиг

0110 1111 01|00 -6*2


+ 0110 6*16
0101 01|00 84
сдвиг

0110 1010 1|001 84*2 2)


- 0110 6*16
0100 1|001 72
сдвиг

0110 1001 |0011 72*2


- 0110 6*16
0011 |0011 48
сдвиг

0011 |0111 Остаток=48/16=3 3)

В данном примере получено правильное значение остатка. Однако, если после


выполнения последнего цикла остаток отрицательный, что соответствует
четному результату, то реальный остаток находился в делимом перед началом
выполнения последней операции вычитания, при которой он стал
отрицательным.

Пример:

Пусть A = 5 = 01012, B = 23 = 0001 01112

A B

0101 0001 0111|


- 0101
1100 0111|
сдвиг

35
0101 1000 111|0
+ 0101
1101 111|0
сдвиг

0101 1011 11|00


- 0101
0110 11|00
сдвиг

0101 1101 1|001


- 0101 остаток в случае, если результат -
1001 1|001 четный.
сдвиг

0101 0011 |0010


+ 0101
1000 |0010
сдвиг

1000 |0100

Очевидно, A/B = 4, а остаток должен быть равен 3.

Обратите внимание, при результате 410=01002 остаток еще не находился в


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

Таким образом, для восстановления остатка при использовании данного


алгоритма требуется либо модификация алгоритма - выделение
дополнительных n разрядов для его сохранения перед каждой операцией, и
обновление после нее, если он положителен, либо выполнение деления с
восстановлением остатка.

4.3. Деление. Дополнительные алгоритмы.

В предыдущей главе был рассмотрен простой алгоритм деления, аналогичный


делению “столбиком”. Однако существует большое количество алгоритмов,
позволяющих выполнить деление. Эти алгоритмы могут быть разделены на три
группы [3].

Первая группа – рекуррентные алгоритмы, подобные рассмотренному в 4.1


алгоритму деления. Существуют вариации, позволяющие ускорить деление за
счет вычисления в одной итерации одновременно нескольких разрядов
результата. К этой группе относится метод SRT, применяемый, в основном, в
аппаратных реализациях и позволяющий вычислять 2 и более разряда частного
за одну итерацию. Основная сложность заключается в определении группы бит
частного на каждой итерации. В частности, фирмой Intel лишь в процессорах на

36
архитектуре Core 2 было реализовано деление с получением четырех бит
результата за один такт (Radix-16 division). Все предыдущие архитектуры
использовали без существенных изменений делитель, вычислявший 2 бита
результата за одну итерацию (Radix-4 division), реализованный в процессорах
фирмы Intel еще в процессоре Pentium.
Достоинства - возможность получения остатка от деления по завершении
операции. Простота реализации для случая вычисления одного разряда за одну
итерацию.
Недостатки - низкое быстродействие (линейная сходимость).

Вторая группа - итеративные функциональные методы, например метод


Ньютона.
Достоинства - в отличие от методов первой группы, быстродействие которых
можно описать линейной сходимостью, эти методы имеют квадратичную
сходимость или сходимость более высоких порядков.
Недостатки - более сложный базовый шаг вычислений и необходимость
использования операции умножения. Отсутствие остатка как результата
вычислений в дополнение к частному. Возможность получения неточного
результата (например, при некорректной реализации вместо правильного
результата 2 можно получить 1.999999(9) при любом количестве итераций).

Третий класс - алгоритмы с нелинейной сходимостью (переменной задержкой).


Требуют различное время для выполнения операции в зависимости от
операндов.
Достоинства – потенциально могут быть быстрее рассмотренных.
Недостатки – более сложная реализация сопряженных устройств и
синхронизации.

В программных и аппаратных реализациях на микроконтроллерах и


микропроцессорах используются, как правило, алгоритмы первого и второго
классов.

Для аппаратной реализации деления целых чисел и чисел с фиксированной


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

При наличии функции умножения для программной реализации деления чисел с


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

4.4. Метод Ньютона для деления.


В отличие от рекуррентных алгоритмов, вычисляющих значение операции
деления на основе операций сложения, вычитания и сдвига, деление методом
Ньютона использует также операцию умножения. Таким образом, этот
алгоритм может быть использован на контроллерах и процессорах, имеющих
операцию умножения, для выполнения операции деления и, в общем случае, для
вычисления значения функций, которые могут быть вычислены методом
Ньютона (касательных).

Значение операции деления может быть определено как

37
a 1
Q  a*
b b
То есть, деление может быть сведено к операции умножения и операции
определения значения функции
1
f ( x) 
x
При применении метода Ньютона определяется функция, которая равна 0
(имеет корень) при значении переменной, равном вычисляемому значению. Так,
для деления может быть применена функция
1
F ( x)  b,
x

которая равна 0 при x=1/b и процесс вычисления обратного значения сводится к


нахождению данного корня функции F(x).

Метод Ньютона основан на замене F(x) в точке начального приближения x=x0


касательной, пересечение которой с осью x дает первое приближение значения
корня функции x1, после чего строится касательная в точке x1, и пересечение с
осью x дает приближение x2.

Таким образом, итерационный процесс схождения к корню реализуется


формулой
F (x )
xn1  xn  ' n
F ( xn )
Так как
1
F ' ( x)   2 ,
x
то
xn1  xn (2  b * xn )

Процесс продолжается, пока разница между предыдущим и новым значением не


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

Процесс обеспечивает сходимость, если соблюдается условие

F ( x) * F '' ( x)  0 ,

что дает для функции деления

1
0 x
b

Такой метод используется во многих современных процессорах. Например,


процессоры цифровой обработки сигналов фирмы Analog Devices семейства
SHARC не имеют команды деления чисел с плавающей запятой, но имеют
операции выборки приближенного значения обратного из ПЗУ, с применением
которого в качестве начального приближения за небольшое количество
итераций может быть получен результат с требуемой точностью.

38
4.5. Метод Ньютона для вычисления квадратного корня.
Аналогичный подход может быть использован для вычисления других функций,
например, для вычисления квадратного корня могут быть использованы
следующие уравнения:

1
Q x  x*
x

1
f ( x) 
x

1
F ( x)  b
x2

2
F ' ( x)  
x3

xn 1  0.5 * xn (3  b * xn2 )

Область сходимости
1
0 x
b

39
4.6. Применение таблицы начальных приближений.

Рассмотрим процесс вычислений (рис.6).

F(x)

1/b
0
x0 x1 x2
x
-b

Рис. 6

В качестве первого приближения берется x0, которое должно находиться в


области сходимости алгоритма. Для вычисления обратного должно соблюдаться
условие x0<1/b. В случае, если b велико, результат вычисления обратного
значения может быть достаточно мал. Таким образом, если информация о
величине b отсутствует, для обеспечения сходимости требуется брать первое
приближение достаточно малым, меньшим любого возможного результата
работы алгоритма. В то же время, для малых значений аргумента значения
последующих итераций (x1,x2 и т.д.) могут находиться на расстоянии, меньшем,
чем заданная точность и алгоритм остановится.

Поэтому при реализации обычно создается таблица начальных приближений,


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

Таблица начальных приближений может быть построена только по мантиссе,


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

При этом выборка значения приближения по 8 старшим битам мантиссы с


точностью 8 бит, для чего требуется реализовать массив отсчетов объемом 256
байт, позволяет в 3 итерации метода Ньютона-Рафсона получить точность,
превышающую точность представления данных в формате single.

4.7. Метод разложения в ряд


Вычисление результата деления также может быть реализовано с применением
разложения в степенной ряд.

Значение функции в точке y, принадлежащей окрестности точки p может быть


определено через ряд Тейлора.

40
( y  p) 2 ( y  p) n ( n )
f ( y)  f ( p)  ( y  p) f ( p)  f ( p)  ...  f ( p)  ...
2! n!

В случае деления, мы можем вычислить значение обратного делителя и


умножить его на делимое.

a
q  a  g (b) ,
b

1
g (b) 
b

Вычисление ряда Маклорена (ряда Тэйлора для p=0) было бы более


эффективным с вычислительной точки зрения, но для этой функции это
невозможно. Произведем замену

y  b 1

и получим разложение в ряд Маклорена в точке 0:

1
g ( y)   1  y  y 2  y 3  y 4  ...
(1  y)

Для обеспечения сходимости степенного ряда необходимо выполнить условие

y 1
,

однако для ускорения сходимости желательно использовать значения, как


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

1 b  2

делится на 2 сдвигом на 1 разряд вправо, таким образом,

0 .5  b '  1

 0 .5  y '  0 ,

т.е

y '  0.5

и ряд сходится.

41
Эту коррекцию нужно учесть по завершении итераций и умножить полученное
частное на два для получения правильного результата.

Формула вычисления обратного может быть представлена в виде

g ( y)  1  y  y 2  y 3  y 4  ...  (1  y)(1  y 2 )(1  y 4 )(1  y 8 )...

При этом одна итерация потребует двух умножений.

Литература
1. А.Я.Савельев "Прикладная теория цифровых автоматов" - М.:ВШ, 1987
2. Й. Янсен "Курс цифровой электроники" - М.:Мир, 1987
3. S. Oberman, M.Flynn. An Analysis Of Division Algorithms And
Implementations. CSL-TR-95-675, Computer Systems Laboratory, Dept. of EE
and CS, Stanford Univ.

42