Міністерство освіти і науки України
Національний університет “Львівська політехніка”
/
Лабораторна робота № 4
Тема:
ОБЧИСЛЕННЯ ЕЛЕМЕНТАРНИХ ФУНКЦІЙ НА МАТЕМАТИЧНОМУ СПІВПРОЦЕСОРІ
Мета: Познайомитися з принципами роботи математичного співпроцесора та оволодіти навиками використання вбудованих елементарних математичних функцій та реалізації розгалужень.
ТЕОРЕТИЧНІ ВІДОМОСТІ
Команди порівняння чисел
У центральному процесорі команди умовних переходів виконуються відповідно до значень окремих бітів регістра прапорців процесора. У арифметичному співпроцесорі існують спеціальні команди порівнянь, за наслідками виконання яких, встановлюються біти кодів умов в регістрі стану:
FCOM – порівняння;
FICOM – порівняння цілих чисел;
FCOMP - порівняння дійсних чисел і вилучення зі стеку;
FICOMP - порівняння цілих чисел і вилучення зі стеку;
FCOMPP - порівняння і подвійне вилучення зі стеку (ST(0), ST(1)); FTST - порівняння операнда з нулем;
FXAM - аналіз операнда на тип числа (скінчене число, денормалізоване число, нуль, некінечність, ...).
Команда FCOM віднімає вміст операнда, розміщеного в оперативній пам’яті, від значення у вершині стеку ST(0). Результат віднімання нікуди не записується і покажчик вершини стеку ST не змінюється.
Позначимо операнд команди порівняння як “x”. Нижче, приведемо значення бітів кодів умови після виконання команди “FCOMx”:
C3 = 0, C0 = 0 ST(0)> x
C3 = 0, C0 = 1 ST(0)< x
C3 = 1, C0 = 0 ST(0)= x
C3 = 1, C0 = 1 ST(0) і x непорівнювані
Остання комбінація виникає при спробі порівняння не чисел, невизначеностей або нескінченості, а також в деяких інших випадках.
Операндами команди FICOM є 16- або 32-розрядні цілі числа, а в решті - аналогічна команді FCOM.Команди FCOMP і FICOMP аналогічні, відповідно, командам FCOM і FICOM, за винятком того, що після виконання операнд вилучається зі стеку.
Команда FCOMPP виконує ті ж дії, що і FCOM, але вона після виконання вилучає зі стеку обидва операнди, що брали участь в порівнянні.
Команда FTST призначена для порівняння операнду з нулем. Після її виконання коди умов встановлюються згідно з наведеним нижче:
C3 = 0, C0 = 0 ST(0)> 0
C3 = 0, C0 = 1 ST(0)< 0
C3 = 1, C0 = 0 ST(0)= 0
C3 = 1, C0 = 1 ST(0) і 0 непорівнювані
Команда FXAM аналізує вміст ST(0). Після її виконання встановлюються коди умов, згідно яких можна визначити знак числа, його скінченність або нескінченність, нормалізованість і т.д. Біт C1 містить знак числа, що аналізується: 0 -додатний, 1 – від’ємний. За допомогою біта C0 можна визначити, є число скінченим або нескінченим: 0 - скінчене число, 1 - нескінчене. Для скінчених чисел подальша класифікація може проводитися за вмістом кодів умов C2 і C3:
C3 = 0, C0 = 0 Ненормалізоване число
C3 = 0, C0 = 1 Нормалізоване число
C3 = 1, C0 = 0 Нульове число
C3 = 1, C0 = 1 Число денормалізоване
Аналогічно, для нескінчених чисел коди умов C2 і C3 мають наступні значення:
C3 = 0, C0 = 0 Нечисло
C3 = 0, C0 = 1 Нескінчене число
C3 = 1, C0 = 0 Порожнє число
C3 = 1, C0 = 1 Порожнє число
Для реалізації порівняння чисел необхідно за допомогою команди “FSTSW AX” переписати вміст регістра стану співпроцесора в регістр AX центрального процесора. Далі вміст регістра AH переписати в регістр прапорів центрального процесора за допомогою команди SAHF. Біти кодів умов співпроцесора відображаються (проектуються) на регістр прапорів центрального процесора так, що без додаткових дій, можна використовувати команди умовних переходів, але тільки беззнакового типу.
Наприклад, в наступному фрагменті програми виконується перехід до мітки compute, якщо операнди рівні:
.586
...
fcoм
0 <= ST(0) <= pi/4.
fstsw ах
sahf
je compute
...
Трансцендентні команди
Трансцендентні команди призначені для обчислення наступних функцій:
тригонометричні (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/x = tg(ST(0)). Для сучасних співпроцесорів x = 1, а y = tg(ST(0)).
Після виконання команди число у розташовується в ST(0), а число x заноситься у вершину стеку (тобто записується в ST(1)). Для старих співпроцесорів (Intel 8087, 80287) аргумент команди FPTAN повинен бути
нормалізованим і знаходиться в межах:
Таблиця 4.1.
Результати обчислень інструкції FPTAN
ST(0) джерело
ST(0) приймач
або +
виняткова ситуація
-
-R або +R
від -R до +R
-0
-0
+0
+0
нечисло
Нечисло
Примітка: R – скінченне дійсне число
Для нових співпроцесорів аргумент команди FPTAN повинен бути поданий в радіанах в межах ±263. Результати обчислень в залежності від вхідних даних подані у таблиці нижче.
Якщо аргумент є більшим або меншим, ніж ±263, то тангенс необхідно шукати сумісним використанням команди FPREM і FPTAN перевіряючи прапорець С2 до повного знаходження значення тангенсу.
Користуючись знайденим значенням часткового тангенса, можна обчислити інші тригонометричні функції за наступними формулами:
sin(z) = 2·(y/x) / (1 + 2·(y/x)); cos(z) = (1 - 2·(y/x)) / (1 + 2·(y/x)); tg(z/2) = y/x;
ctg(z/2) = x/y;
cosec(z) = (1 + 2·(y/x)) / 2·(y/x); sec(z) = (1 + 2·(y/x)) / (1 - 2·(y/x)).
Де z - значення, що знаходилося в ST(0) до виконання команди FPTAN, x і у - значення в регістрах ST(0) і ST(1), відповідно.
Команда FPATAN обчислює частковий арктангенс z = arctg(ST(1)/ST(0)) = arctg(x/y). Перед виконанням команди числа x і у розташовуються в ST(1) і ST(0), відповідно. Аргументи команди FPATAN повинні знаходиться в межах: 0 ≤ x < y < +. Результат записується в ST(1), а операнд в ST(0) вилучається зі стеку. Таким чином результат після виконання інструкції розміщується у ST(0).
Команда FYL2X обчислює вираз y·log2(x), операнди x і у розміщуються, відповідно в ST(0) та ST(1). Операнди вилучаються зі стеку, а результат записується в стек. Параметр x повинен бути додатнім числом.
Користуючись результатом виконання цієї команди, можна обчислити логарифмічні функції, наступним чином:
Логарифм за основою два: log2(x) = FYL2(x). Натуральний логарифм:
logе(x) = logе(2)·log2(x) = FYL2X(logе(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), а у - 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).
Команди керування
Команди, керування, призначені для роботи з нечисловими регістрами співпроцесора. Деякі команди мають альтернативні варіанти. Мнемоніки цих команд можуть починатися з FN або F. Перший варіант відповідає командам “Без очікування”. Для таких команд процесор не перевіряє, чи зайнятий співпроцесор виконанням команди, тобто біт зайнятості B не перевіряється. Особливі випадки також ігноруються.
Варіанти команд “З очікуванням” діють так само, як і звичайні команди співпроцесора.
Ось список команд керування для співпроцесора:
FNSTCW (FSTCW) - записати управляюче слово (записує вміст регістра управління в оперативну пам’ять).
FLDCW - завантажити управляюче слово (завантажує регістр управління з оперативної пам’яті і, як правило, використовується для зміни режиму роботи співпроцесора).
FNSTSW (FSTSW) - записати слово стану (записує вміст регістра стану в оперативну пам’ять).
FNSTSW AX (FSTSW AX) - записати слово стану в AX (записує вміст регістра стану в регістр AX центрального процесора, де можливий аналіз вмісту за допомогою команд умовних переходів).
FNCLEX (FCLEX) - скинути особливі випадки (скидає прапорці особливих випадків в регістрі стану співпроцесора, також скидаються біти ES і B).
FNINIT (FINIT) - ініціалізувати співпроцесор (ініціалізує регістр стану, регістр управління, і регістр тегів таким чином:
регістр управління - проектна нескінченість, округлення до найближчого, розширена точність, всі особливі випадки замасковані;
регістр стану - B=0 (біт зайнятості скинутий), код умови не визначений, ST=ES=0, прапорці особливих випадків встановлені в нуль;
регістр тегів - усі поля регістру тегів містять значення 11 (порожній регістр));
FNSTENV (FSTENV) - записати оточення (записує в пам’ять вміст всіх регістрів, окрім числових, у визначеному форматі. Команда корисна при обробці особливих випадків);
FLDENV - завантажити оточення (завантажує регістри, збережені командою FNSTENV);
FNSAVE (FSAVE) - записати повний стан (діє аналогічно команді FNSTENV, але додатково зберігає вміст числових регістрів);
FRSTOR - відновити повний стан (діє аналогічно команді FLDENV, але додатково відновлює вміст числових регістрів);
FINCSTP - збільшити покажчик стека SP на 1;
FDECSTP - зменшити покажчик стека SP на 1;
FFREE - звільнити регістр (визначає числовий регістр ST, вказаний як операнд, як порожній, записуючи у відповідне поле регістра тегів значення 11);
FNOP - порожня команда, немає операції (не робить жодних дій); FSETPM - встановлює захищений режим роботи (переводить
співпроцесор в захищений режим роботи).
Виконання лабораторної роботи №4
ЗАВДАННЯ
Створити *.exe програму, яка реалізовує обчислення, заданого варіантом виразу. Вхідні дані повинні вводитися з клавіатури, як дійсні числа. Програма повинна складатися з двох модулів:
головний модуль – створюється мовою С і має забезпечити ввід необхідних даних, виклик асемблерної процедури для обчислення виразу та вивід результату обчислень; модуль безпосередніх обчислень – здійснює всі необхідні арифметичні дії з
використанням математичного співпроцесора.
Переконатися у правильності роботи кожного модуля зокрема та програми загалом.
Скласти звіт про виконану роботу з приведенням тексту програми та коментарів до неї.
Дати відповідь на контрольні запитання.
Варіант №3
Source.cpp
#include <stdio.h>
#include <math.h>
#include<conio.h>
extern "C" float calc(double, float, float,float);
int main()
{
int SIZE = 0;
printf("Input mass size: ");
scanf("%d", &SIZE);
double *mass = new double[SIZE];
double *RES = new double[SIZE];
float C;
float D;
float B;
for (int i = 0; i < SIZE; i++)
{
printf("Input a[%d]: ", i);
scanf("%lf", &mass[i]);
}
printf("Input C: ");
scanf("%f", &C);
printf("Input D: ");
scanf("%f", &D);
printf("Input B: ");
scanf("%f", &B);
for (int i = 0; i < SIZE; i++){
RES[i] = calc(mass[i], C, D,B);
printf("ANSWER[%d]", i);
printf("\n");
printf("ASM:The result is:%lf ", RES[i]);
printf("\n");
if (C>D)
printf("C++:The result is:%Lf ", (tan(mass[i] + C / 4) - 12 * D) / (mass[i] * B - 1));
else if (C <= D)
printf("C++:The result is:%Lf ", ((-2*C)-sin(mass[i]/D)+53)/ ((mass[i]/4)-B));
printf("\n");
getch();
}
return 0;
}
Assembler.asm
.386
.model flat,c
option casemap:none
PUBLIC calc
.data
K1 dword 1.0
K2 dword -2.0
K4 dword 4.0
K12 dword 12.0
K53 dword 53.0
; A = qword ptr [ebp+8]
C1 dword 0
D dword 0
B dword 0
.code
calc proc
push ebp
mov ebp, esp
mov eax, [ebp+16]
mov C1,eax
mov eax,[ebp+20]
mov D,eax
mov eax, [ebp+24]
mov B,eax
FINIT
;(c>d)???
fld C1
fcom D
fstsw ax
sahf
jbe NO
YES:
;Y =(tan(mass[i] + C / 4) - 12 * D) / (mass[i] * B - 1)
fld C1
fld K4
fdiv
fld qword ptr [ebp+8]
fadd
fptan ; st(1)
fld D
fmul K12
fsub st(2),st(0)
fld qword ptr [ebp+8]
fmul B
fsub K1
fld st(3)
fld st(1)
fdiv
jmp RESULT
NO:
;X= (-2*C-sin(mass[i]/D)+53)/ ((mass[i]/4)-B))
fld K2
fmul C1
fld qword ptr [ebp+8]
fdiv D
fsin
fld st(0)
fsub st(2),st(0)
fld st(2)
fadd K53
fld st(0)
fld qword ptr [ebp+8]
fdiv K4
fsub B
fdiv
RESULT:
pop ebp
ret
calc endp
end
Фото виконання програми:
/
Алгоритм виконання програми:
На початку програми відбувається зчитування значення з клавіатури за допомогою мови С, значення А записуються в масив, після чого потрібно ввести значення С та D, адже вони будуть однаковими при виконанні програми, після введення даних, відбувається вхід в цикл де буде здійснено подальше обчислення прикладу, обчислення буде проведено мовою Асемблер.
.data
K1 dword 1.0
K2 dword -2.0
K4 dword 4.0
K12 dword 12.0
K53 dword 53.0
; A = qword ptr [ebp+8]
C1 dword 0
D dword 0
B dword 0
В даному блоці ми оголосили та ініціалізували всі змінні крім масиву А, значення його не будуть записуватись в додаткову зміну, звернення до значень буде здійснено напряму через адресу в стеці співпроцесора.
FINIT
;(c>d)???
fld C1
fcom D
fstsw ax
sahf
jbe NO
Даний код ілюструє порівняння двох чисел, після виконання буде проведене обчислення при варіанті коли С більше за D, або при варіанті коли С менше за D.
fstsw ax – записує вміст регістра в ОП.
SAHF - вміст регістра АН переписує в регістр прапорців центрального процесора.
При варіанті коли С більше за D, то буде виконано наступне обчислення
YES:
;Y =(tan(mass[i] + C / 4) - 12 * D) / (mass[i] * B - 1)
fld C1
fld K4
fdiv
fld qword ptr [ebp+8]
fadd
fptan
fld D
fmul K12
fsub st(2),st(0)
fld qword ptr [ebp+8]
fmul B
fsub K1
fld st(3)
fld st(1)
fdiv
jmp RESULT
Після мітки YES ми завантажуємо значення С, після чого відбувається завантаження значення константи К4(4), за допомогою команди fdiv ми ділимо ці два числа, результат буде записано в ST(0). Команда fld qword ptr [ebp+8] завнатжує в стек співпроцесора значення масиву(одне число), команда fadd додає числа в стеку співпроцесора ST(0) та ST(1), після чого обраховується тангенс суми попередніх чисел. Завантажуємо число D , і множимо його на константу К12, результат віднімаємо від значення тангенса. Завантажуємо значення масиву в стек і множимо його на зміну B після чого віднімаємо 1, після всіх обчислень ми за допомогою команди fld st(3) завантажуємо значення тангенса в ST(0), fld st(1) – завантажує значення (mass[i] * B - 1) в ST(0), тим самим зсуваєм значення тангенса в ST(1), fdiv – команда яка ділить значення тангенса на (mass[i] * B - 1)
NO:
;X= (-2*C-sin(mass[i]/D)+53)/ ((mass[i]/4)-B))
fld K2
fmul C1
fld qword ptr [ebp+8]
fdiv D
fsin
fld st(0)
fsub st(2),st(0)
fld st(2)
fadd K53
fld st(0)
fld qword ptr [ebp+8]
fdiv K4
fsub B
fdiv
Після мітки NO ми завантажуємо значення константи К2 в стек співпроцесора і множимо його на С1, далі ми завантажуємо значення масиву(число) в стек співпроцесора, ділимо його на значення змінної D, далі ми здійснюємо обчислення синуса, за допомогою команди fld st(0) ми завантажуємо значення синуса в ST(0), і віднімаємо від ST(2) ST(0), в ST(2) у нас буде знаходитись значення -2*C,
За допомогою команди fld st(2) ми заватнажуємо значення ST(2) в ST(0), і додаємо до нього значення константи К53, після чого ми заносимо значення (-2*C-sin(mass[i]/D)+53) в ST(0). Завантажуємо значення масиву (число), в стек співпроцесора, ділимо його на константу К4(4), і віднімаємо від результату обчислення значення змінної B. В кінці ми здійснюємо ділення (-2*C-sin(mass[i]/D)+53)/ ((mass[i]/4)-B)) і дістаємо результат обчислення
Висновок:
Після виконання даної лабораторної роботи я познайомилась з принципами роботи математичного співпроцесора та оволоділа навиками використання вбудованих елементарних математичних функцій та реалізації розгалужень.