|
Последний пример использования
сопроцессора 8087 - вычисление
синуса угла.У сопроцессора 8087 нет команды вычисления функции
SIN; самое большее, что он может - это
выполнить команду FPTAN,
нахождение частичного тангенса.Чтобы выполнить операцию SIN,
воспользуемся этой командой, а также
командой FPREM (частичный
остаток).
Программа, вычисляющая SIN, показана на
Фиг. 7.27.Эта
программа вычисляет и печатает синусы
углов от 1/2 до 6 с шагом 1/2
радиана.Выдача программы аналогична выдаче следующей программы на
языке Бейсик:
10FOR X = .5 TO 6.0 STEP .5
20PRINT SIN(X)
30NEXT X
Для печати результатов используется
подпрограмма на Фиг. 7.25.
Microsoft (R) Macro Assembler Version 5.001/1/80 04:05:01
Фиг. 7.27 Вычисление синуса угла Page1-1
PAGE,132
TITLEФиг. 7.27 Вычисление синуса угла
0000STACKSEGMENT STACK
00000040[DW64 DUP (?)
????
]
0080STACKENDS
0000CODESEGMENT
ASSUMECS:CODE,DS:CODE,ES:CODE
EXTRNFLOAT_ASCII:NEAR
00000001NUM_ANGLEDW1
00020002DEN_ANGLEDW2
0004????STATUSDW?
00060004FOURDW4
= 0040C3EQU40H
= 0004C2EQU04H
= 0002C1EQU02H
= 0001C0EQU01H
000893 A3 AE AB 20 E1 ABERROR_MSGDB'Угол слишком большой', 10, 13, '$'
A8 E8 AA AE AC 20 A1
AE AB EC E8 AE A9 0A
0D 24
001FSINPROCFAR
001F1EPUSHDS
00202B C0SUBAX, AX
002250PUSHAX
00238C C8MOVAX, CS
00258E D8MOVDS, AX
00278E C0MOVES, AX
0029DO_AGAIN:
00299B DB E3FINIT;-----ST(0)-----;-----ST(1)------
002C9B DF 06 0000 RFILDNUM_ANGLE;;
00319B DE 36 0002 RFIDIVDEN_ANGLE; X = Угол;
Фиг. 7.27 (a) Процедура SIN (начало)
00369B D9 EBFLDPI; PI; X
00399B DE 36 0006 RFIDIVFOUR; PI/4; X
003E9B D9 C9FXCH; X; PI/4
00419B D9 F8FPREM; R; PI/4
00449B DD 3E 0004 RFSTSWSTATUS
00499BFWAIT
004A8A 26 0005 RMOVAH, BYTE PTR STATUS+1
004EF6 C4 04TESTAH, C2
005175 55JNZBIG_ANGLE
0053F6 C4 02TESTAH, C1; Определяется, необходимо ли вычитание PI/4
005674 05JZDO_R; Если 0, то не необходимо вычитание PI/4
00589B DE E1FSUBRPST(1), ST(0); A = PI/4-R; ?
005BEB 06JMPSHORT DO_FPTAN
005DDO_R:
005D9B D9 C9FXCH; PI/4; R
00609B D8 D9FCOMP; R; ?
0063DO_FPTAN:
00639B D9 F2FPTAN; OPP; ADJГде OPP/ADJ=Tan(A)
;-----Опеределение того, что нужно - синус или косинус
0066F6 C4 42TESTAH, C3 or C1
00697A 03JPEDO_SINE
006B9B D9 C9FXCH; ADJ; OPP
006EDO_SINE: ; D; N
;-----Вычисление N/SQR(N**2 + D**2)
006E9B D8 8E 0000 UFMULST(0); D**2; N
00739B D9 C9FXCHST(1); N; D**2
00769B D9 C0FLDST(0); N; N; D**2
00799B D8 8E 0000 UFMULST(0); N**2; N; D**2
007E9B DC 06 0000 UFADDST(2); N**2 + D**2; N; D**2
00839B D9 FAFSQRT; SQR(N2 + D2); N; D**2
00869B DE F1FDIVRPST(1); SIN(X);
D**2
00899B D9 C9FXCHST(1); D**2; SIN(X)
008C9B D8 D9FCOMP; SIN(X); ?
008FF6 C4 01TESTAH, C0
009274 03JZSIGN_OK
00949B D9 E0FCHS
0097SIGN_OK:
0097E8 0000 E CALLFLOAT_ASCII
009AFF 06 0000 RINCNUM_ANGLE
009E83 3E 0000 R 0DCMPNUM_ANGLE, 13
00A377 02JARETURN_INST
00A5EB 82JMPDO_AGAIN
00A7RETURN_INST:
00A7CBRET
00A8BIG_ANGLE:
00A88D 16 0008 RLEADX, ERROR_MSG
00ACB4 09MOVAH, 9H
00AECD 21INT21H
00B0CBRET
00B1SINENDP
00B1CODEENDS
ENDSIN
Фиг. 7.27 (a) Процедура SIN (продолжение)
A>SIN
4.79425539E-001
8.41470985E-001
9.97494987E-001
5.98472144E-001
1.41120008E-001
-3.50783228E-001
-7.56802495E-001
-9.77530118E-001
-9.58924275E-001
-7.05540326E-001
-2.79415498E-001
2.15119988E-001
Фиг. 7.27 (b) Вывод процедуры SIN
Фиг. 7.27 Вычисление синуса угла
В первой части программы происходит ее
инициализация для работы
в качестве файла типа .EXE.Затем сопроцессор 8087 загружает два
целых числа и делит их, формируя исходный
угол.Это - пример
использования двух целых чисел для
порождения числа с плавающей
точкой (в данном случае 1/2), что нельзя
сделать непосредственно с
помощью ассемблера.
Как вы помните из тригонометрии, синус -
периодическая функция.
То есть функция дает один и тот же
результат в случае исходных
чисел, различающихся ровно на 2*PI.Поэтому первой задачей
подпрограммы SIN является замена исходного
угла соответствующим
значением, лежащим в диапазоне
0 <= X < 2*PI
В команде FPTAN требуется, чтобы угол
находился в диапазоне
0 <= X < PI/4
Это означает, что даже если угол и меньше
2*PI, мы должны
уменьшить его еще, чтобы он удовлетворял
ограничениям команды
FPTAN.К счастью, если исходный угол уменьшен до значения,
меньшего PI/4, все еще можно определить
верное значение
тригонометрических функций.Чтобы это сделать, надо знать, в каком
месте исходного диапазона от 0 до 2*PI
находился исходный угол.
Нужное уменьшение угла выполняет команда
FPREM.Она не только
вычисляет остаток, но и три младших бита
частного, определяемого в
течение процесса поиска остатка.Эти три бита команда записывает в
слово состояния.Следовательно, хотя мы и уменьшили угол до
значения одной восьмой исходного
диапазона, все же можно определить
октант, в который попадет угол.Зная его, можно найти формулу
вычисления синуса с помощью
тригонометрических преобразований.
Таблица на Фиг. 7.28 показывает связь
между исходным октантом и
методом вычисления синуса угла.В таблице предполагается, что
число R - это остаток от уменьшения
исходного угла до значения
меньше PI/4.Номер октанта появляется в разрядах C3 = C1 = C0
после выполнения команды FPREM.
С помощью этой таблицы мы можем определить
формулу вычислений,
применяемую в каждом случае выполнения
программы.После загрузки
значения угла в радианах программа
загружает число и делит его на
4, чтобы использовать в команде
FPREM.В этот момент
"захватывается" слово
состояния.Если процесс поиска остатка
не
завершился на этом единственном шаге, это
означает, что исходный
угол был больше 2**64.Следовательно, его значение настолько больше
максимально возможного при вычислениях
тригонометрических функций,
что мы отбрасываем это число, как слишком
большое.Этого не
происходит со значениями, выбранными в
примере, но здесь для
иллюстрации введена такая проверка.
Октанты
C0C3C1ДиапазонSIN(X) = :
-----------------------------------------------------
0 0 00PI/4SIN(R)
0 0 1PI/4PI/2COS(PI/4-R)
0 1 0PI/23*PI/4COS(R)
0 1 13*PI/4PISIN(PI/4-R)
1 0 0PI5*PI/4-
SIN(R)
1 0 15*PI/43*PI/2-
COS(PI4-R)
1 1 03*PI/27*PI/4-
COS(R)
1 1 17*PI/42*PI-
SIN(PI/4-R)
(R - остаток, 0<R<PI/4)
-----------------------------------------------------
Фиг. 7.28 SIN(X) в восьми секторах
Программа проверяет разряд C1 в регистре
состояния, чтобы
определить, должна ли она использовать
остаток R, или его надо
вычесть из PI/4.Так как PI/4 еще находится в одном из регистров,
это сделать просто.Если вычитание не требуется, команда FCOMP
удаляет из стека ненужное значение PI/4.
Затем команда FPTAN вычисляет частичный
тангенс.Результат
работы команды показан, как OPP/ADJ
(сокращения от английских слов
Opposite (противоположный) и Adjacent
(соседний)), что равно
тангенсу угла R или PI/4-R, в зависимости
от того, что было
выбрано.С помощью этих двух чисел теперь можно опеределить синус
или косинус угла.Например, синус, заданный парой чисел
OPP/ADJ,
можно вычислить по формуле
SIN(X) = OPP/SQR(OPP**2+ADJ**2), где
TAN(X) = OPP/ADJ
Чтобы вычислить косинус, нужно числитель
заменить на ADJ.Мы
решаем, нужен ли синус или косинус,
анализируя запомненные
описатели октанта, т.е.проверяя значения разрядов C3 и C1.
Команда TEST выделяет эти значения, а
команда JPE делает переход,
если они оба нулевые или оба
единичные.В этом случае мы вычисляем
синус; если же они различны, мы вычисляем
косинус, что достигается
заменой местами значений OPP и ADJ в стеке
регистров.
Далее следующие команды сопроцессора 8087
вычисляют значение
синуса (или косинуса) по значению
частичного тангенса.
Единственный шаг, который еще надо выполнить
- это определение
окончательного знака результата.В случае синуса результат
отрицателен, если угол находится в
октантах от четвертого до
седьмого.Проверка разряда C0 определяет верный знак результата.
Затем программа FLOAT_ASCII, показанная на
Фиг. 7.25, печатает
число в плавающем формате.Управление возвращается назад, к началу
цикла, если еще не пройдены все
октанты.Нижняя часть Фиг. 7.27
иллюстрирует результат выполнения этой
программы.
|