Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Архитектура вычислительных систем и Ассемблер с приложением методических указаний к лабораторным работам. Учебное пособие
.pdf
2.6. Альтернативная арифметика 81
Подобная арифметика в целом циклична по модулюP, так что, в частности,
(P − 1) + 1 = 0; ассоциативна и коммутативна.
Некоторые операции выполняются сложнее, чем в позиционных системах счис-
ления. Такие операции называются
немодульными.
Это, прежде всего,
сравнение
то есть установление порядка (установление равенства — модульная операция),
и все операции, в реализации которых оно используется:
– контроль переполнения;
– деление;
– квадратный корень и т. п.
Из-за немодульности сравнения расширение модулярного представления на все
целые числа возможно только в виде значения со знаком. При использовании
для отрицательных чисел кода со смещением
(−x) → P − x
кода
нет простого способа отличить отрицательное число от
x → x + ξ
или дополнительного
положительного. На вещественные числа модулярное представление естественным
путём не расширяется.
Модулярная арифметика позволяет реализовать очень быстрые вычисления
над неотрицательными целыми числами, а также контролировать корректность результата в процессе вычислений, что позволяет обнаруживать аппаратные ошибки.
2.6.3. Арифметика с насыщением
— Чего? — спросил Дуб.
— Стоять и не выпускать, — перевела Мергиона.
А. В. Жвалевский, И. Е. Мытько.
Личное дело Мергионы или Четыре чёртовы дюжины
,
В предыдущих разделах рассматривалась циклическая арифметика, то есть,
если обрабатываемые числа находятся в диапазоне
[Min,Max]
,то
Max+1=
Minи Min− 1=Max. Это основная используемая в ЭВМ схема.
Для некоторых задач в случае выхода за границы допустимого диапазона удобнее схема с насыщением — если «правильный» результат операции превышает
наибольшее представимое значение
Max
, то он считается равным
Max
, если он
меньше Min, то, соответственно, формируется результат Min.
Таким образом, Max+1=Maxи Min− 1=Min.
Арифметика с насыщением коммутативна, но неассоциативна, в частности
(Max− 1) − (Max− 1) = 0,
но
Max− (1 + Max)+1=Max−Max+1=1.
Процессоры семейства x86 поддерживают арифметику с насыщением в рамках
команд расширения MMX.

82 Глава 2. Представление данных
Арифметика чисел с плавающей запятой (раздел 2.8.2) не является арифметикой с насыщением.
2.7. Битовые операции
— Умная игра, — подтвердил Дубль таким же низким голосом,
— клеточек куда больше, чем в крестиках-ноликах!
А. В. Жвалевский, И. Е. Мытько.
Девять подвигов Сена Аесли. Подвиги 5-9
Битовые операции — операции, производимые над цепочками битов.
Существует три основных класса битовых операций:
– поразрядные операции (not, and, or, xor);
– операции расширения (увеличения разрядности);
– сдвиги.
Все поразрядные операции рассматривают операнды как однородные цепочки
битов; операции расширения и сдвиги делятся на два типа — знаковые, особым
образом обрабатывающие старший (знаковый) бит цепочки, и беззнаковые.
2.7.1. Поразрядные операции
Почему так? Потому что развитое тело
легче изучать, чем клеточку тела.
К. Маркс. Капитал
Поразрядные операции применяются к каждому разряду операнда (для унарных
операций) или к каждой паре соответствующих разрядов операндов (для бинарных
операций) независимо от соседних разрядов.
Так как один двоичный разряд может принимать только два значения, которые
можно трактовать как «ложь» и «истина», набор поразрядных операций обычно
включает все логические операции (таблица 2.7).
Логические операции над разрядами
Таблица 2.7
ab
00
01
10
11
¬a (not, !) a ∧ b (and, &) a ∨ b (or, |) a ⊕ b (xor,ˆ)
1
0
000
011
011
110

2.7. Битовые операции 83
Для поразрядных операций применяются различные обозначения, наиболее
популярные из них показаны в шапке таблицы 2.7. В последующих примерах
используются обозначения, принятые в языке C++ (!, &, |,ˆ).
Результат в каждом разряде рассчитывается независимо от соседних (отсутствует перенос между разрядами). Разрядность результата соответствует разрядности операндов, для бинарных операций разрядность обоих операндов должна быть
одинаковой. Поразрядные операции не могут быть знаковыми или беззнаковыми:
обработка старшего бита не отличается от остальных.
Таким образом, поразрядное отрицание (битовая инверсия, дополнение до
единицы) — это унарная операция, где к каждому разряду единственного операнда
применяется логическое отрицание:
!2
= ! 0000 0010 = 1111 1101 (2.65)
10
Полученное значение можно трактовать как
тат как знаковый, либо как
25310, если интерпретировать его как беззнаковый. Ни
−310, если интерпретировать резуль-
одно из этих двух значений здесь не будет «правильным» или «ошибочным».
Если трактовать операнды как знаковые и представленные в дополнительном
коде, ∀x :!x = −x − 1.
При этом необходимо помнить, что если операнд
210имеет б´ольшую раз-
рядность (и, соответственно, включает больше ведущих нулей), то и результат
будет содержать больше ведущих единиц. Соответственно, в общем случае разрядностиNзначение
!210в знаковой интерпретации будет иметь значение
−310,
а в беззнаковой — (2N− 3)10.
Поразрядное «и» (конъюнкция) — бинарная операция, к каждой паре разрядов
операндов применяется логическое «и»:
3
&510= 0000 0011 & 0000 0101 = 0000 0001 = 1
10
10
(2.66)
разряд результата равен нулю, если хотя бы один операнд содержит ноль в соответствующем разряде.
При помощи поразрядного «и» можно получить неотрицательный остаток от
деления целого числаxна
2n. В этом случае второй операнд («маска») состоит
из n единиц: x mod 2n= x &(2n− 1).
mod 810= 18910&710=
189
10
= 1011 1101 & 0000 0111 = 0000 0101 = 5
10
(2.67)
Поразрядное «или» (дизъюнкция) — бинарная операция, к каждой паре разрядов операндов применяется логическое «или»:
3
10|510
= 0000 0011 | 0000 0101 = 0000 0111 = 7
10
(2.68)

84 Глава 2. Представление данных
разряд результата равен единице, если хотя бы один операнд содержит единицу
в соответствующем разряде.
Поразрядное исключающее «или» (также называется сложением по модулю
два, но, в отличие от арифметической операции сложения, нет переноса между
разрядами) — бинарная операция, к каждой паре разрядов операндов применяется
исключающее «или»:
3
10ˆ510
= 0000 0011ˆ0000 0101 = 1111 0110 = −1010= 246
10
(2.69)
разряд результата равен единице, если один и только один операнд содержит
единицу в соответствующем разряде.
Так как для одного разряда
∀b ∈{0, 1} :1⊕ b = ¬b
, для чисел любой
разрядности верно ∀x :(−1)ˆx =!x.
Поразрядные логические операции используются как в алгоритмах криптографии, так и, в некоторых ситуациях, для ускорения арифметических вычислений.
Последнее возможно, только если один из операндов является константой специфического вида.
2.7.2. Расширение целых чисел
...Даже самые абстрактные категории <...> представляют
собой в такой же мере и продукт исторических условий
и обладают полной значимостью только для этих условий
и в их пределах.
К. Маркс. Капитал
Часто необходимо увеличить разрядность числа, сохранив его значение. В C++
подобное происходит, в частности, при присваивании переменных разного размера:
1 int i;
2 short int s = -1;
3 i=s; // расширение short int до int (знаковое)
Операция увеличения разрядности называется расширениемn-разрядного числаxдоmразрядов (
m>n
). Младшиеnразрядов результата совпадают с расши-
ряемым значением x, старшие m − n должны быть как-то инициализированы.
Существует две операции расширения, по-разному инициализирующие расширяемую часть:
беззнаковое расширение — расширяемая часть заполняется нулями (такая опе-
–
рация сохраняет значение беззнаковой интерпретации x);
знаковое расширение — расширяемая часть заполняется значением знакового
–
бита (сохраняет значение знаковой интерпретации x).

2.7. Битовые операции 85
В языках высокого уровня знаковость расширения определяется знаковостью используемых типов (так, в C++ расширение
до
unsigned
unsigned
— беззнаковое). В ассемблере знаковое и беззнаковое рас-
short intдоint
— знаковое,
short
ширение выполняются разными командами.
В таблице 2.8 показаны примеры знакового и беззнакового расширения восьмибитных чисел до шестнадцати бит.
Знаковое и беззнаковое расширение
Таблица 2.8
Значение
bin hex dec
знак
dec
беззн
x (8 бит) 0000 0000 00 00
беззнаковое
−−−−−−→ 16 бит 0000 0000 0000 0000 0000 00
x
знаковое
−−−−−→ 16 бит 0000 0000 0000 0000 0000 00
x
x (8 бит) 0000 0001 01 11
беззнаковое
−−−−−−→ 16 бит 0000 0000 0000 0001 0001 11
x
знаковое
−−−−−→ 16 бит 0000 0000 0000 0001 0001 11
x
x (8 бит) 0000 1111 0F 15 15
беззнаковое
−−−−−−→ 16 бит 0000 0000 0000 1111 000F 15 15
x
знаковое
−−−−−→ 16 бит 0000 0000 0000 1111 000F 15 15
x
x (8 бит) 1000 0000 80 −128 128
беззнаковое
−−−−−−→ 16 бит 0000 0000 1000 0000 0080 128 128
x
знаковое
x
−−−−−→ 16 бит 1111 1111 1000 0000 FF80 −128 65 408
x (8 бит) 1111 1111 FF −1 255
беззнаковое
−−−−−−→ 16 бит 0000 0000 1111 1111 00FF 255 255
x
знаковое
−−−−−→ 16 бит 1111 1111 1111 1111 FFFF −1 65 535
x
Каждая строка таблицы соответствует одному значению (цепочке битов). Во
втором столбце показано его двоичное представление, в третьем — шестнадцатеричное, в четвёртом — десятичное представление его знаковой интерпретации,
в пятом — десятичное представление беззнаковой интерпретации. Строки сгруппированы по три — восьмибитное значениеx, его беззнаковое расширение до
шестнадцати бит и знаковое расширение до того же размера.
Видно, что для неотрицательных (в знаковой интерпретации) чисел знаковое
и беззнаковое расширение выполняется одинаково.

86 Глава 2. Представление данных
2.7.3. Битовые сдвиги
Заметьте:
справа налево двигать могу
и слева направо.
В. В. Маяковский. Человек
Битовые сдвиги — семейство бинарных операций с несимметричными операндами. Один из операндов представляет собой цепочку битов, второй — неотрицательное целое число — величину сдвига. Цепочка битов смещается вправо или
влево на указанное количество битов. Разрядность результата равна разрядности
операнда-цепочки. Кроме явных операндов и результата, в сдвигах используется
флаг переноса CF.
Сдвиг наnразрядов эквивалентен повторённомуnсдвигу на один разряд,
соответственно, для простоты ниже рассматривается только сдвиги на один бит.
Как было сказано выше, сдвиги различаются направлением — вправо (в сторону младших разрядов) или влево (в сторону старших). Кроме того, при сдвиге
крайний с одной стороны разряд выдвигается за пределы разрядной сетки (его значение попадает в ячейку флага переносаCF), а крайняя ячейка с другой стороны
освобождается.
В зависимости от способа заполнения освободившейся ячейки различаются
следующие типы сдвига:
– знаковые (арифметические);
– беззнаковые (логические);
– циклические.
Ниже различные виды сдвигов рассматриваются на примере восьмибитных значений.
Знаковый и беззнаковый сдвиги вправо
В случае беззнакового (логического) сдвига вправо (в сторону младших разрядов) освободившийся старший разряд инициализируется нулём (рис. 2.3, а).
В случае знакового (арифметического) сдвига вправо — копией знакового бита
(рис. 2.3, б).
Логический сдвиг вправо соответствует беззнаковому делению на2с остатком, арифметический — знаковому. Знаковое деление при этом выполняется по
правилам математики, подразумевающим неотрицательный остаток даже при отрицательном делимом, то есть при делении минус единицы на2частное равно минус
единице, а остаток — плюс единице.
Остаток как для знакового, так и для беззнакового деления на2сдвигом
CF
на один бит равен биту
(вышедшему за разрядную сетку младшему биту
исходного числа).

2.7. Битовые операции 87
N 0
0
1 1 1 1 1 0 1 1
shr
0 1 1 1 1 1 0 1 1
а)
= 251
= 125
CF
CF
?
CF
N 0
1 1 1 1 1 0 1 1
sar
1 1 1 1 1 1 0 1 1
б)
= −5
= −3
CF
CF
?
CF
Рис. 2.3. Беззнаковый (а) и знаковый (б) сдвиги вправо
Сдвиг вправо наnразрядов соответствует делению на
2n, причём в случае
знакового (арифметического) сдвига отрицательных чисел также выполняется
«математическое» деление, подразумевающее неотрицательный остаток.
Во многих языках программирования (в частности, в C/C++) считается, что
при делении знаковых чисел остаток может быть отрицательным, то есть при
делении минус единицы на2частное будет равно нулю, а остаток — минус единице.
Команды знакового деления ЭВМ реализуют именно эту схему.
Результат «программистского» деления отрицательного числаxна
2nв общем
случае не равен результату «математического» (подразумевающего неотрицательный остаток и рассчитываемого сдвигом
случае, когдаxделится на
2nнацело. Для всех остальных
x sar n
). Они совпадают только в том
x<0
результат «про-
граммистского» деления будет на единицу больше.
Таким образом, чтобы получить при помощи арифметического сдвига значение
«программистского» частного, необходимо до сдвига прибавить к отрицательному
делимому значение
2n− 1
. Для положительного делимого или нуля коррекция не
требуется.
Знаковый и беззнаковый сдвиг влево
В случае сдвига влево (в сторону старших разрядов) освободившийся младший
бит инициализируется нулём (рис. 2.4).
Знаковый и беззнаковый (арифметический и логический) сдвиги влево не различаются. Сдвиг влево на один бит эквивалентен умножению на2(так как разрядность результата равна разрядности исходной цепочки, неважно — знаковому или
нет). Коррекция операндов не требуется.
Битовые сдвиги выполняются гораздо быстрее, чем умножение и деление с помощью специализированных команд. Соответственно, умножение и деление на
специальные константные значения часто выполняются оптимизирующими компиляторами при помощи сдвигов или комбинации сдвигов и сложения.

88 Глава 2. Представление данных
CF
CF
?
CF
N 0
0 0 0 0 0 1 0 1
shl/sal
0 0 0 0 1 0 1 00
0
=5
=10
Рис. 2.4. Знаковый (беззнаковый) сдвиг влево
Циклические сдвиги
В случае простого циклического сдвига освободившаяся ячейка с одной стороны замещается разрядом, вышедшим с другой стороны за разрядную сетку (рис. 2.5,
а) и б).
CF
N 0
а)
N 0
б)
CF
Рис. 2.5. Простой циклический сдвиг: а) влево, б) вправо
В случае циклического сдвига через флаг переноса освободившаяся ячейка
инициализируется значением флага переносаCF, а ячейка
CF
замещается разря-
дом, вышедшим за разрядную сетку (рис. 2.6, а) и б). Таким образом, результат
зависит не только от операндов, но и от текущего значения CF.
CF
N 0
а)
N 0
б)
Рис. 2.6. Циклический сдвиг через флаг переноса: а) влево,
б) вправо
Если простой циклический сдвигN-разрядного числа циклически перемещает разрядыN-битной цепочки, то сдвиг через флаг переноса —
(N +1)
цепочки (операнд + CF).
Циклические сдвиги не эквивалентны какой-либо арифметической операции.
Они широко используются в криптографии.
CF
-битной

2.8. Представление вещественных чисел 89
2.8. Представление вещественных чисел
Опять скажу: никто не обнимет необъятного!
К. П. Прутков. Плоды раздумья. Мысли и афоризмы
Какой бы код ни использовался, с помощьюNбитов
лучить только
более
2Nзначений. При этом, в отличие от целых чисел, вещественных значений
в любом диапазоне
2Nразных кодовых комбинаций и, соответственно, представить не
[ν1,ν2] ⊆ R
бесконечно много (причём эта бесконечность
b
...b1b0можно по-
N−1
несчётна, то есть количество вещественных чисел, помещающихся на любом интервале, превышает общее число существующих целых чисел).
Таким образом, для того, чтобы закодировать вещественные числа, необходимо не только ограничить допустимый диапазон, но и проредить его внутреннюю
часть. Большую часть вещественных чисел описываемого диапазона
[ν1,ν2] ⊆ R
невозможно точно представить в ЭВМ.
Представление вещественных чисел основано на описанной в разделе 2.3.4
позиционной двоичной записи.
2.8.1. Представление вещественных чисел с фиксированной запятой
Сие редко встречающееся явление
требует двоякого объяснения.
М. В. Ломоносов. Явление Венеры на Солнце
Представим неотрицательное вещественное числоXв виде бесконечной двоичной дроби
(2.11)
, округлим доnразряда после запятой, обозначив результат
округления˘X:
X ≈˘X = x
· 2k+ ...+ x1· 21+ x0· 20+ x−1· 2−1+ ...+ x−n· 2−n=
k
x
= x
· 2k+ ...+ x1· 2+x0+
k
=
xk...x1x0,x−1...x−n, 0 xi< 2 — целые
−1
2
+ ...+
x
−n
=
n
2
(2.70)
и последовательно запишем цифры
с младшей цифры
x−nи младшего бита
x−n,...xkв биты кода
b0. После старшей цифры
b0,...b
N−1
xkзаписываются
, начиная
нули. Таким образом, изNбитов, отведённых под представление числа, для
дробной части используется n, для целой остаётся N −n.
˘
X = b
N−1
N−n−1
· 2
+ ...+ b
b
=
N−1
n+1
...bn,b
· 2+bn+
...b
n−1
b
n−1
+ ...+
2
0
b
0
=
n
2
(2.71)

90 Глава 2. Представление данных
Двоичная запятая, отделяющая дробную часть от целой, всегда расположена между
разрядамиnи
n − 1
. Соответственно, такой способ кодирования называется
представлением с фиксированной запятой.
Целая часть числа может принимать значения от0до
0=0,00 ...00до1 −
от
1
= 0,11 ...11
n
2
(всего
2nзначений). Таким образом,
числа, представимые в формате с фиксированной запятой с помощью
из которых отведены под дробную часть, заключены в диапазоне
На каждом полуинтервале
[ν, ν +1)
находится
2nчисел, представимых в виде
2
N−n
− 1
, дробная —
N
N−n
0, 2
бит,
−
1
n
2
с фиксированной запятой с n-битной дробной частью.
Точность двоичных чисел с фиксированной запятой
При округлении вещественного числа
X ∈0, 2
после запятой абсолютная погрешность округления не превышает
X −˘X
<
N−n
доnдвоичных разрядов
1
n
2
1
:
n
2
(2.72)
относительная погрешность увеличивается при уменьшении абсолютной величины
числа:
X −˘X
X
<
1
2n·|X |
(2.73)
n
.
Таким образом, абсолютная погрешность округления при сохранении числа
X
в формат с фиксированной запятой постоянна и зависит только от характеристик
формата (от количества n бит, отведённых под дробную часть).
Арифметика чисел с фиксированной запятой
n−1
n
получим целое число:
...b0=
b
n−1
+ ...+
2
n−1
· 2
n−1
+ ...+ b0· 20=
b
0
=
n
2
Нетрудно заметить, что при умножении (2.71) на 2
n
= b
=2
N−1
n
·b
· 2
N−1
N−1
=
2
· 2
+ ...+ b
b
N−1
·˘X =2n· b
N−n−1
...bnb
+ ...+ b
n+1
n−1
· 2
...b0= x, x ∈{0, 1,...2N− 1}
N−1
n+1
n+1
+ bn· 2n+ b
...bn,b
· 2+bn+
(2.74)
то есть существует взаимно однозначное соответствие между числами с фиксированной запятой и целыми числами в диапазоне0, 2N− 1:
x
˘
X =
n
2
(2.75)
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
