Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скляров И. Изучаем Assembler за 7 дней (2010).pdf
Скачиваний:
1335
Добавлен:
23.02.2015
Размер:
2.11 Mб
Скачать

http://www.sklyaroff.ru

99

5.3.2. Вычисления с плавающей запятой

Числа с плавающей точкой — это числа, представляемые в экспоненциальной форме, т. е. в таком виде:

X = S×M×Nq,

где X – вещественное число, S — знак числа,

M — мантисса числа,

N — основание системы счисления,

q — экспонента называемая часто порядком (целое). Порядок (q) определяет положение запятой в мантиссе.

Например, в числе 6.6261x10-27: M=6.6261, N=10, q=-27, знак числа "+" (S).

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

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

Сопроцессор для преставления вещественных чисел с плавающей запятой руководствуется стандартом IEEE Standard for Binary Floating-Point Arithmetics, IEEE 754-1985.

Согласно этому стандарту старший разряд двоичного представления вещественного числа всегда кодирует знак числа: 0 – положительное, 1 – отрицательное. Остальная часть разбивается на две части: экспонента и мантисса.

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

(рис. 5.1):

короткий (одинарной точности) — для хранения числа отводится 32 бита. Под мантиссу отводится 24 бита.

длинный (двойной точности) — для хранения числа отводится 64 бита. Под мантиссу отводится 54 бита.

расширенный (повышенной точности) — для хранения числа отводится 80 битов. Под мантиссу отводится 64 бита.

Рис. 5.1. Форматы чисел с плавающей запятой согласно стандарту IEEE 754-1985

Согласно стандарту IEEE 754-1985 порядок должен храниться в смещенном формате, который определяется по следующей формуле:

q = p + значение смещения

Значение q часто называют характеристикой.

Для коротко формата вещественных чисел значение смещения равно +127, для длинного +1023, для расширенного +16383.

Кроме того, согласно IEEE 754-1985 мантисса должна быть представлена в нормализованном виде:

M = 1.дробная часть

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

http://www.sklyaroff.ru

100

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

Для определения чисел с плавающей запятой в программе можно использовать директивы MASM: real4 — для коротких, real8 — для длинных и real10 — для расширенных вещественных чисел. Пример:

Number1 real4 45.56 ; короткий формат Number2 real8 45.56 ; длинный формат Number3 real10 45.56 ; расширенный формат

Кроме этого, для определения чисел с плавающей запятой можно воспользоваться директивами DD — для коротких, DQ — для длинных и DT — для расширенных вещественных чисел. Однако директивы DD, DQ, DT не сообщают об ошибке, если число не содержит точки.

Примеры:

dd 45.56 ; короткий формат dq 45.56 ; длинный формат

dt 45.56 ; расширенный формат

В данных директивах можно использовать символ "е" для экспоненциальной формы. Предыдущие определения c использованием "e" будут выглядеть следующим образом:

dd 0.4556e2 ; короткий формат dq 0.4556e2 ; длинный формат

dt 0.4556e2 ; расширенный формат

Так как числа с плавающей запятой довольно сложно устроены, то к ним нельзя сразу применять обычные арифметические инструкции ассемблера, такие как ADD, SUB, MUL, DIV. Чтобы вести правильные арифметические расчеты с числами с плавающей запятой нужно каким-то образом выделять мантиссу и экспоненту, производить множество вспомогательных действий и результат снова упаковывать в

32, 64 или 80 бита.

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

Сопроцессор предоставляет программисту восемь регистров (R0-R7) для хранения данных и еще пять вспомогательных регистров (CWR,SWR,TWR,IPR,DPR) (рис. 1.9).

Команды сопроцессора не могут оперировать реальными названиями регистров хранения данных R0...R7, вместо них используются логические обозначения этих регистров ST(0)...ST(7).

В отличие от регистров центрального процессора регистры данных сопроцессора не работают независимо, а организованы в виде стека. Вершина стека всегда называется ST(0), затем идут ST(1), ST(2) и так далее до ST(7). Обычно вместо ST(0) используют краткое обозначение ST. Кстати, название ST происходит от английского слова STack (стек). Как и у ЦП, стек сопроцессора растет к регистрам с меньшими адресами.

Особенностью такого стека является еще то, что при помещении значения в него вершина стека ST смещается, а вместе с ней смещаются все логические номера ST(1)...ST(7) при этом смещение происходит циклически (по кольцу). Например, если текущая вершина стека ST соответствует регистру R3, то после записи в этот стек значения оно будет записано в регистр R2 и станет называться ST, при этом соответствующим образом сместятся все логические номера, а элемент соответствующий R0 станет соответствовать R7. Смещаются циклические только логические номера ST(1)...ST(7), а не сами значения в стеке!

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

http://www.sklyaroff.ru

101

Из-за стековой структуры регистров сопроцессора форма записи математических выражений для FPU является обратной польской нотацией. Согласно этой нотации все операторы математического выражения указываются после своих операндов, например выражение a+b в польской нотации будет выглядеть как ab+, а выражение cos(x) как x cos. При этом отпадает необходимость использовать скобки, например: выражение (A+B)*(C+D)-E будет записано как AB+CD+*E-.

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

Сопроцессор работает параллельно с центральным процессором, поэтому раньше (до 287) необходимо было для синхронизации работы двух процессоров перед многими командами FPU вставлять команду FWAIT (или WAIT), чтобы приостановить выполнение ЦП до окончания вычислений сопроцессором. В последующих сопроцессорах эта команда встроена в инструкции FPU, поэтому ее использовать не обязательно. Но остались не ожидающие команды, которые можно узнать по приставке "N". Например, команды FSAVE и FNSAVE выполняют одно и тоже действие, но перед FSAVE компилятор всегда добавляет команду FWAIT.

Если в команде присутствует суффикс "P", то это означает, что команда после своего выполнения выталкивает число из стека сопроцессора (помечает ST(0) как пустой и увеличивает TOP на один). К таким командам, например, относятся FADDP, FSUBP, FMULP, FDIVP, FCOMP.

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

Перед началом использования сопроцессора в программе необходимо выполнить его инициализацию командой FINIT. Эта команда устанавливает значения по умолчанию во всех регистрах и флагах FPU, в том числе обнуляет регистры данных ST(0)-ST(7).

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

Ассемблирование и линковка выполняется обычным образом: ml fpuadd.asm

Листинг 5.2. Сложение двух вещественных чисел (fpuadd.asm)

.model tiny

.code

org 100h

start:

finit

 

; инициализировать сопроцессор

 

 

 

fld

num1

; загружаем 1-й операнд в ST

 

fld

num2

; 2-й операнд в ST, 1-й операнд в ST(1)

 

fadd

 

; складываем, сумма помещается в ST

 

fstp

result

; скопировать из ST в result

 

ret

 

 

num1

dd

45.56

; первое вещественное число

num2

dd

30.13

; второе вещественное число

result

dt

?

; сюда будет помещен результат

 

end

start

 

В листинге 5.3 показан более сложный пример — вычисление арктангенса по следующей формуле:

http://www.sklyaroff.ru

 

102

y 2* arctg(

x2

 

 

)

x2

1

Где -1 ≤ x ≤ +1.

В обратной польской нотации это уравнение будет выглядеть следующим образом:

x x * x x * 1 + sqrt / arctg 2 *

Обратите внимание, что в программе мы не выполняем явно деление (для чего обычно используется инструкция FDIV), т. к. это деление автоматически выполняет сама функция FPATAN.

Листинг 5.3. Вычисления арктангенса по формуле: y = 2*arctg(x2/sqrt(x2+1)) (fpuarctg.asm)

.model tiny

.code

org 100h

start:

finit

 

; инициализировать сопроцессор

 

 

 

fld

x

; x в стек

 

fld

x

; x в стек еще раз

 

fmul

 

; перемножить (соответствует x^2)

 

fld

st(0)

; сделать копию st(0)

 

fld1

 

; поместить в стек 1,0

 

fadd

 

; выполнить операцию x^2+1

 

fsqrt

 

; взять корень sqrt(x^2+1)

 

fpatan

 

; арктангенс arctg(x^2/sqrt(x^2+1))

 

fild

y

; число 2 в стек

 

fmul

 

; перемножить 2*arctg(x^2/sqrt(x^2+1))

 

ret

 

 

x

dd

0.5

; значение x

y

dd

2

; значение y

end start

5.3.2.1. Сравнение вещественных чисел

Если вам понадобится в программе сравнить два вещественных числа, то у вас не получится использовать обычные инструкции сравнения, такие как TEST и CMP, т. к. они, во-первых, предназначены для сравнения целых чисел, а, во-вторых, не работают со стеком FPU. В сопроцессоре предусмотрены специальные команды сравнения: FTST, FCOM, FUCOM, FICOM, FCOMI и др. (см. их описание в разд. 5.4.4). Эти команды сравнения сохраняют результат сравнения в трех битах (флагах) C0, C2 и C3 специального слова состояния сопроцессора (регистр состояния

SWR, см. разд. 5.4.2.2).

С помощью команды FSTSW AX можно сохранить значение регистра SWR в регистр AX, а затем командой SAHF перевести флаги C0, C2 и C3 в ZF, PF и CF. Это позволяет использовать условные команды Jcc, CMOVcc, FCMOVcc и др., точно также как после команды CMP.

Например, в следующем фрагменте программы выполняется переход к метке error, если операнды в ST(0) и ST(1) несравнимы:

fcom