Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Арифметические команды




Сопроцессор использует шесть основных типов арифметических команд:

- Fxxx

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

- Fxxx память

Источник берется из памяти, приемником является верхушка стека ST(0). Указатель стека ST не изменяется, команда действительна только для операндов с одинарной и двойной точностью

- Fixxx память

Аналогично предыдущему типу команды, но операндами могут быть 16- или 32-разрядные целые числа

- Fxxx ST, ST(i)

Для этого типа регистр ST(i) является источником, а ST(0) - верхушка стека - приемником. Указатель стека не изменяется

- Fxxx ST(i), ST

Для этого типа регистр ST(0) является источником, а ST(i) - приемником. Указатель стека не изменяется

- FxxxP ST(i), ST

Регистр ST(i) - приемник, регистр ST(0) - источник. После выполнения команды источник ST(0) извлекается из стека

Строка "xxx" может принимать следующие значения:

- ADD - Сложение

- SUB - Вычитание

- SUBR - Обратное вычитание, уменьшаемое и вычитаемое меняются местами

- MUL - Умножение

- DIV - Деление

- DIVR - Обратное деление, делимое и делитель меняются местами

Кроме основных арифметических команд имеются дополнительные арифметические команды:

- FSQRT - Извлечение квадратного корня

- FSCALE - Масштабирование на степень числа 2

- FPREM - Вычисление частичного остатка

- FRNDINT - Округление до целого

- FXTRACT - Выделение порядка числа и мантиссы

- FABS - Вычисление абсолютной величины числа

- FCHS - Изменение знака числа

По команде FSQRT вычисленное значение квадратного корня записывается в верхушку стека ST(0).

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

ST(0) = ST(0) * 2n, где -215 <= n <= +215

В этой формуле n - это ST(1).

Команда FPREM вычисляет остаток от деления делимого ST(0) на делитель ST(1). Знак результата равен знаку ST(0), а сам результат получается в вершине стека ST(0).

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

- 0 - Остаток от деления, полученный в ST(0), меньше делителя ST(1), команда завершилась полностью

- 1 - ST(0) содержит частичный остаток, программа должна еще раз выполнить команду для получения точного значения остатка

Команда RNDINT округляет ST(0) в соответствии с содержимым поля RC управляющего регистра.

Команда FABS вычисляет абсолютное значение ST(0). Аналогично, команда FCHS изменяет знак ST(0) на противоположный.

Трансцендентные команды

Трансцендентные команды предназначены для вычисления следующих функций:

- тригонометрические (sin, cos, tg,...)

- обратные тригонометрические (arcsin, arccos,...)

- показательные (xy, 2x, 10x, ex)

- гиперболические (sh, ch, th,...)

- обратные гиперболические (arsh, arch, arcth,...)

Вот список всех трансцендентных команд математического сопроцессора:

- FPTAN Вычисление частичного тангенса

- FPATAN Вычисление частичного арктангенса

- FYL2X Вычисление y*log2(x)

- FYL2XP1 Вычисление y*log2(x+1)

- F2XM1 Вычисление 2x-1

- FCOS Вычисление cos(x)

- FSIN Вычисление sin(x)

- FSINCOS Вычисление sin(x) и cos(x) одновременно

Команда FPTAN вычисляет частичный тангенс ST(0), размещая в стеке такие два числа x и y, что y/x = tg(ST(0)).

После выполнения команды число y располагается в ST(0), а число x включается в стек сверху (то есть записывается в ST(1)). Аргумент команды FPTAN должен находится в пределах:

0 <= ST(0) <= pi/4

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

- sin(z) = 2*(y/x) / (1 + (y/x)2)

- cos(z) = (1 - (y/x)2) / (1 + (y/x)2)

- tg(z/2) = y/x;

- ctg(z/2) = x/y;

- cosec(z) = (1 + (y/x)2) / 2*(y/x)

- sec(z) = (1 + (y/x)2) / (1 - (y/x)2)

Где z - значение, находившееся в ST(0) до выполнения команды FPTAN, x и y - значения в регистрах ST(0) и ST(1), соответственно.

Команда FPATAN вычисляет частичный арктангенс:

z=arctg(ST(0)/ST(1))=arctg(x/y).

Перед выполнением команды числа x и y располагаются в ST(0) и ST(1), соответственно. Аргументы команды FPATAN должен находится в пределах:

0 < y < x

Результат записывается в ST(0).

Команда FYL2X вычисляет выражение y*log2(x), операнды x и y размещаются, соответственно, в ST(0) и ST(1). Операнды извлекаются из стека, а результат записывается в стек. параметр x должен быть положительным числом.

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

- Логарифм по основанию два: log2(x) = FYL2(x)

- Натуральный логарифм: loge(x) = loge(2) * log2(x) = FYL2X(loge(2), x) = FYL2X(FLDLN2, x)

- Десятичный логарифм: log10(x) = log10(2) * log2(x) = FYL2X (log10(2), x) = FYL2X(FLDLG2, x)

Функция FYL2XP1 вычисляет выражение y*log2(x+1), где x соответствует ST(0), а y - ST(1). Результат записывается в ST(0), оба операнда выталкиваются из стека и теряются.

На операнд x накладывается ограничение: 0 < x < 1 - 1/sqrt(2)

Команда F2XM1 вычисляет выражение 2x-1, где x - ST(0). Результат записывается в ST(0), параметр должен находиться в следующих пределах: 0 <= x <= 0,5

Команда FCOS вычисляет cos(x). Параметр x должен находиться в ST(0), туда же записывается результат выполнения команды.

Команда FSIN аналогична команде FCOS, но вычисляет значение синуса ST(0).

Команда FSINCOS вычисляет одновременно значения синуса и косинуса параметра ST(0). Значение синуса записывается в ST(1), косинуса - в ST(0).

 

Константы FPU

FLD1 - Поместить в стек 1,0

FLDZ - Поместить в стек +0,0

FLDPI - Поместить в стек число π

FLDL2E - ­­Поместить в стек log2(e)

FLDL2T - Поместить в стек log2(10)

FLDLN2 - Поместить в стек ln(2)

FLDLG2 - Поместить в стек lg(2)

Все эти команды помещают в стек (то есть уменьшают ТОР на один и помещают в ST(0)) соответствующую часто используемую константу.

Пример

Пример вычисления выражения:

Анализ особенностей задачи.

Возможны две ситуации деления на ноль:

, если . Например, .

, если . Например, .

В то же время ситуация, когда , является допустимой.

.Model Small

.586

.Data

res dq 0

a dq 3.0

b dq 10.0

const25 dw 25

const4 dw 4

const5 dw 5

status dw 0

.Code

;Вывод вещественного числа

; аргумент - количество цифр дробной части

length_frac Equ [BP+4]

; локальные переменные

ten Equ word ptr [BP-2]

temp Equ word ptr [BP-4]

OutFloat Proc Near

ENTER 4, 0; выделим в кадре стека 4 байта под локальные переменные

MOV ten, 10

ftst; определяем знак числа

fstsw AX

SAHF

JNC @positiv

MOV AL, '-'; если число отрицательное - выводим минус

INT 29h

fchs; и получаем модуль числа

@positiv:

fld1; загружаем единицу

fld st(1); копируем число на вершину стека

fprem; выделим дробную часть

fsub st(2), st; отнимем ее от числа - получим целую часть

fxch st(2); меняем местами целую и дробную части

XOR CX, CX; обнуляем счетчик

; далее идет стандартный алгоритм вывода целого числа на экран

@1:

fidiv ten; делим целую часть на десять

fxch st(1); обменяем местами st и st(1) для команды fprem

fld st(1); копируем результат на вершину стека

fprem; выделим дробную часть (цифру справа от целой части)

fsub st(2), st; получим целую часть

fimul ten; *10

fistp temp; получаем очередную цифру

PUSH temp; заталкиваем ее глубже в стек

INC CX; и увеличим счетчик

fxch st(1); подготовим стек к следующему шагу цикла (полученное частное на вершину, в st(1) - 1)

ftst; проверим не получили ли в частном 0?

fstsw AX

SAHF

JNZ @1; нет - продолжим цикл

@2:; извлекаем очередную цифру, переводим её в символ и выводим.

POP AX

ADD AL, '0'

INT 29h

LOOP @2

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

fstp st; сначала проверим, есть ли дробная часть

fxch st(1)

ftst

fstsw AX

SAHF

JZ @quit; дробная часть отсутствует

MOV AL, '.'

INT 29h; если присутствует - выведем точку

MOV CX, length_frac; помещаем в счетчик длину дробной части

@3:

fimul ten; умножим на 10

fxch st(1); подготовка для fprem - меняем st и st(1) местами и

fld st(1); копируем число на вершину

fprem; отделим дробную часть от целой

fsub st(2), st; и оставляем дробную

fxch st(2)

fistp temp; выталкиваем полученное число из стека в temp

MOV AX, temp; по дробной части идем слева, значит число выводим сразу, без предварительного сохранения в стек

OR AL, 30h; перевод в ascii

INT 29h; на экран

fxch st(1); подготовим стек к следующему шагу цикла (полученное частное на вершину, в st(1) - 1)

ftst

fstsw AX

SAHF; проверим на 0 остаток дробной части

LOOPNE @3

@quit:

fstp; готово. Чистим стек сопроцессора

fstp st

LEAVE; эпилог

RET 2

OutFloat EndP

 

func Proc Far

;PUSHA

finit; инициализация сопроцессора

fld qword ptr[b]; b

fld qword ptr[a]; a b

fcom st(1); сравниваем a и b

fstsw status; сохраняем регистр флагов сопроцессора

MOV AH, byte ptr [status+1]

SAHF; записываем в регистр флагов процессора

JA a_bigger; переход если a больше

JB b_bigger; переход если b больше

; если равны

fild const25; 25 a b

JMP endcalc

a_bigger: ftst; сравнение a с 0

fstsw status; сохраняем регистр флагов сопроцессора

MOV AH, byte ptr [status+1]

SAHF; записываем в регистр флагов процессора

JE error; переход если a=0

fdivp st(1), st(0); b/a

fild const4; 4 b/a

fsubp st(1), st(0); b/a-4

JMP endcalc

b_bigger: fldz; 0 a b

fcomp st(2); сравнение b с 0

; a b

fstsw status; сохраняем регистр флагов сопроцессора

MOV AH, byte ptr [status+1]

SAHF; записываем в регистр флагов процессора

JE error; переход если b=0

fld st(0); a a b

fmul st(1), st(0); a a*a b

fmulp st(1), st(0); a*a*a b

fild const5; 5 a*a*a b

fsubp st(1), st(0); a*a*a-5 b

JMP endcalc

error:

fldz; формируем результат ошибки

endcalc:

fstp res; сохранение результата

RET

func EndP

start:

MOV AX, @data

MOV DS, AX

CALL func

XOR AX,AX

XOR BX,BX

XOR CX,CX

XOR DX,DX

finit; инициализируем сопроцессор

fld res; записываем число стека для вывода

PUSH 10; заталкиваем число знаков после запятой

CALL outfloat

MOV AX,4c00h

INT 21h

End start





Поделиться с друзьями:


Дата добавления: 2015-10-01; Мы поможем в написании ваших работ!; просмотров: 823 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Вы никогда не пересечете океан, если не наберетесь мужества потерять берег из виду. © Христофор Колумб
==> читать все изречения...

2307 - | 2123 -


© 2015-2024 lektsii.org - Контакты - Последнее добавление

Ген: 0.011 с.