- •Содержание
- •Теоретические основы лабораторной работы
- •1.2 Задание
- •1.3 Схема алгоритма
- •1.4 Решение
- •1.5 Ответ
- •Лабораторная работа 2 «Арифметические команды и команды переходов в ассемблере»
- •2.1 Теоретические основы лабораторной работы
- •2.2 Задание
- •2.3 Схема алгоритма
- •2.4 Решение
- •2.5 Ответ
- •Лабораторная работа 3 «Команды работы с массивами и стеком»
- •3.1 Теоретические основы лабораторной работы
- •3.2 Задание
- •3.3 Схема алгоритма
- •3.4 Решение
- •3.5 Ответ
- •Лабораторная работа 4 «Изучение работы математического сопроцессора в среде Assembler»
- •4.1 Теоретические основы лабораторной работы
- •4.2 Задание
- •4.3 Схема алгоритма
- •4.4 Решение
- •4.5 Ответ
- •Лабораторная работа 5 «Команды нахождения тригонометрических функций с помощью математического сопроцессора»
- •5.1 Теоретические основы лабораторной работы
- •5.2 Задание
- •5.3 Схема алгоритма
- •5.4 Решение
- •5.5 Ответ
- •Лабораторная работа 6 «Нахождение суммы ряда с помощью математического сопроцессора»
- •6.1 Теоретические основы лабораторной работы
- •6.2 Задание
- •6.3 Схема алгоритма
- •6.4 Решение
- •6.5 Ответ
- •Список использованных источников
Рисунок 1.1 – Схема алгоритма вычисления исходного выражения
1.4 Решение
#include "stdafx.h"
#include <stdio.h> // стандартный ввод/вывод
#include <iostream> // потоковый ввод/вывод
#include <locale.h>
// функция вычисления выражения (-2*с + d*82)/(a/4 - 1);
bool error = 0;
int calc(int a, int b, int c)
{
int result = 0;
__asm{
mov eax, a
mov ebx, b
mov ecx, c
Sar eax,1 ; арифметический сдвиг вправо на 1, <eax>=a/2
Sar eax,1 ; арифметический сдвиг вправо на 1, <eax>=a/4 dec eax ; <eax>=a/4-l
or eax, eax ; проверка на флаг нуля
je error1
push eax ; в стеке a/4-l
mov eax, 2 ; <eax>=2
imul ecx ; <edx:eax> = c*2
push eax ; в стеке c*2
mov eax, 82 ; <eax>=82
imul ebx ; <edx:eax> = b*82
pop ebx ; <ebx>= c*2
sub eax, ebx ; <eax>= b*82 - 2*c
pop ebx ; <ebx> = a/4-1
; готовимся к делению
cdq ; eax ==> edx:eax
idiv ebx ; <eax>=(-2*с + b*82)/(a/4 - 1)
mov result, eax ; result = eax
jmp end_1
error1:
mov error, 1
end_1:
}
return result; // возвращаем результат вычисления выражения
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_CTYPE,"rus");
printf("Лабораторная работа№1\n");
printf("Вариант: 3\n");
printf("Автор: Галанова Дарья\n");
printf("Группа: 6113\n");
printf("Задание:\n");
printf("Вычисление выражения (-2*с + b*82)/(a/4 - 1)\n\n");
printf("\n");
int a, b, c;
printf("Введите a: ");// стандартный вывод
std::cin >> a;// потоковый ввод
printf("Введите b: ");
std::cin >> b;
printf("Введите c: ");
std::cin >> c;
int res = calc(a, b, c);// вычисление выражения
if(error == 1){
printf("\nОшибка! Деление на ноль. ");}
else{
printf("\nРезультат на ассемблере: ");
printf("%d", res);// вывод результата вычисления выражения
printf("\n\nРезультат на C++: ");
printf("%d", ((-2*c + b*82)/(a/4 - 1)));
}
printf("\n");
system("PAUSE");
return 0;
}
1.5 Ответ
На рисунке 1.2 приведено выполнение программы при вводе верных исходных параметров.
На рисунке 1.3 приведено выполнение программы в случае, когда делитель равен 0, то есть – при вводе некорректных данных. Программа выполняет проверку данного значения и выдает сообщение: «Ошибка! Деление на ноль».
Рисунок
1.2 − Работа программы в случае верного
ввода исходных данных
Рисунок
1.3 − Работа программы в случае ввода
некорректных значений
Лабораторная работа 2 «Арифметические команды и команды переходов в ассемблере»
2.1 Теоретические основы лабораторной работы
Команды, использованные в программе, приведены в таблице 2.1.
Таблица 2.1 Описание команд
Команда |
Назначение |
ADD |
Сложение байтов или слов, содержащих двоичные данные. |
SUB |
Вычитание байтов или слов, содержащих двоичные данные. |
IMUL |
Выполняет операцию умножения для знаковых данных. |
IDIV |
Выполняет операцию деления для знаковых данных. |
DEC |
Уменьшает значение операнда в памяти или регистре на 1. |
CDQ |
Расширяет двойное слово со знаком до размера учетверенного слова (64 бита) со знаком. Используется для подготовки к операции деления, для которой размер делимого должен быть в два раза больше размера делителя. |
OR |
Операция логического ИЛИ над битами операнда назначения. |
CMP |
Сравнивает два операнда. |
JE |
Инструкция условного перехода «перейти, если равно». |
JG |
Инструкция условного перехода «перейти, если больше чем…» |
JL |
Инструкция условного перехода «перейти, если меньше чем…» |
JO |
Инструкция условного перехода «перейти по переполнению». |
JMP |
Используется в программе для организации безусловного перехода. |
NOP |
Используется для передачи управления при конвейерной организации вычислительного процесса. |
MOV |
Команда пересылки данных (из источника в приемник). |
PUSH |
Перемещает данные в стек. |
POP |
Считывает данные из стека. |
Использованные в программе регистры приведены в таблице 2.2.
Таблица 2.2 Описание регистров
Регистр |
Назначение |
EAX |
Регистр общего назначения. Аккумулятор. |
EBX |
Регистр общего назначения. База. |
ECX |
Регистр общего назначения. Счетчик. |
EDX |
Регистр общего назначения. Регистр данных. |
Использованные библиотеки приведены в таблице 2.3.
Таблица 2.3 Описание библиотек
Библиотека |
Назначение |
"stdafx.h" |
Служит для генерации файла предкомпилированных заголовков; в него включено большинство стандартных и используемых в каждом приложении включаемых файлов. Сделано это для того, чтобы ускорить компиляцию проекта. |
<stdio.h> |
Используется для организации стандартного ввода/вывода. |
<iostream> |
Используется для организации потокового ввода/вывода. |
<locale.h> |
Используется для смены кодировки. |
2.2 Задание
В программе необходимо реализовать функцию вычисления заданного условного целочисленного выражения, используя команды сравнения, условного и безусловного переходов на встроенном ассемблере.
Результат X – целочисленный, возвращается из функции регистра eax.
Значения переменных передаются в качестве параметров функции.
В программе реализовать вывод результата на экран.
Все параметры функции 32 битные числа.
Проверку деления на 0 реализовать также на встроенном ассемблере.
В качестве комментария к каждой строке необходимо указать, какой промежуточный результат, в каком регистре формируется.
По возможности использовать команды сдвига.
2.3 Схема алгоритма
На рисунке 2.1 приведена схема алгоритма вычисления функции
Для того чтобы вычислить результат необходимо организовать ввод с клавиатуры исходных данных (параметров a, b). После ввода сравниваются значения введенных параметров. Если a>b, то результат есть значение функции (b/a+5), если a<b, то результат есть значение функции ((a*a-b)/b), иначе результат равен -5.
Рисунок
2.1 – Схема алгоритма вычисления исходного
выражения
2.4 Решение
#include "stdafx.h"
#include <stdio.h> // стандартный ввод/вывод
#include <iostream> // потоковый ввод/вывод
// функция вычисления выражения ((b/a)+5 [a>b]; -5 [a=b]; (a*a-b)/b [a<b]);
bool error = 0;
int calc(int a, int b)
{
int result = 0;
__asm{
mov eax, -5 ; <eax> = -5;
mov ecx, a ; <ecx>=a
mov ebx, b ; <ebx>=b
cmp ecx, ebx ; сравнение a и b
jg l_bigger ; переход если a>b
jl l_smaller ; переход если a<b
mov result, eax ; result = eax
jmp end_1 ; переход на конец программы
l_bigger:
or ecx, ecx ; сравнение a и 0
je error1 ; ошибка деление на ноль
mov eax, ebx ; <eax>=b
cdq ; подготовка деления <edx:eax> = a
idiv ecx ; <eax> = b/a
add eax, 5 ; <eax> = b/a + 5
mov result, eax ; result = eax
jmp end_1 ; переход на конец программы
l_smaller:
or ebx, ebx ; сравнение b и 0
je error1 ; ошибка деление на ноль
mov eax, ecx ; <eax>=a
imul ecx ; <edx:eax> = a*a
jo error1 ; ошибка переполнение
sub eax, ebx ; <eax> = a*a – b
cdq ; подготовка деления <edx:eax>
idiv ebx ; < eax> = (a*a – b)/b
mov result, eax ; result = eax
jmp end_1 ; переход на конец программы
error1:
mov error, 1
end_1:
}
return result ; // возвращение результата
}
int ccalc(int a, int b) //[a>b] (b/a)+5; [a=b] -5; [a<b] (a*a-b)/b
{
if(a>b){
return ((b/a)+5);
}
else{
if(a<b){
return ((a*a-b)/b);
}
else{
return (-5);
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_CTYPE,"rus");
printf("Лабораторная работа№2\n");
printf("Вариант: 3\n");
printf("Автор: Галанова Дарья\n");
printf("Группа: 6113\n");
printf("Задание:\n");
printf("Вычисление выражения с условием:\n\n [a>b]\t(b/a)+5;\n [a=b]\t-5;\n [a<b]\t(a*a-b)/b\n\n");
int a, b;
printf("Введите a: ");// стандартный вывод
std::cin >> a;// потоковый ввод
printf("Введите b: ");
std::cin >> b;
int res = calc(a, b);// вычисление выражения
if(error == 1){
std::cout<<"Ошибка"<<std::endl;
}
else{
printf("\nРезультат на ассемблере: ");
printf("%d", res);// вывод результата вычисления выражения
printf("\n\nРезультат на C++: ");
printf("%d", ccalc(a,b));
}
printf("\n");// стандартный вывод
system("PAUSE");
return 0;
}
2.5 Ответ
На рисунках 2.2, 2.3, 2.4 приведены тестовые примеры выполнения программы при вводе корректных исходных данных. На рисунке 2.5 приведен результат работы программы в случае ввода недопустимых значений, когда делитель равен 0. Программа выполняет проверку данного значения и выдает предупредительное сообщение.
Рисунок
2.2 − Работа программы в случае a>b
Рисунок
2.3 − Работа программы в случае a=b
Рисунок
2.4 − Работа программы в случае a<b
Рисунок
2.5 − Работа программы в случае некорректного
ввода данных
Лабораторная работа 3 «Команды работы с массивами и стеком»
3.1 Теоретические основы лабораторной работы
Команды, использованные в программе, приведены в таблице 3.1.
Таблица 3.1 Описание команд
Команда |
Назначение |
INC |
Увеличивает значение операнда в памяти или регистре на 1. |
CMP |
Сравнивает два операнда. |
JNE |
Инструкция условного перехода «перейти, если не равно». |
JCXZ |
Инструкция перехода внутри текущего сегмента команд в зависимости от некоторого условия. |
LOOP |
Используется для организации цикла со счетчиком в регистре ECX. |
JMP |
Используется в программе для организации безусловного перехода. |
MOV |
Команда пересылки данных (из источника в приемник). |
XOR |
Операция логического исключающего ИЛИ над двумя операндами размерностью байт, слово или двойное слово (побитовое сравнение). |
Использованные в программе регистры приведены в таблице 3.2.
Таблица 3.2 Описание регистров
Регистр |
Назначение |
EAX |
Регистр общего назначения. Аккумулятор. |
EBX |
Регистр общего назначения. База. |
ECX |
Регистр общего назначения. Счетчик. |
EDX |
Регистр общего назначения. Регистр данных. |
ESI |
Регистр общего назначения. Индекс источника. |
Использованные библиотеки приведены в таблице 3.3.
Таблица 3.3 Описание библиотек
Библиотека |
Назначение |
"stdafx.h" |
Служит для генерации файла предкомпилированных заголовков. |
<stdio.h> |
Используется для организации стандартного ввода/вывода. |
<iostream> |
Используется для организации потокового ввода/вывода. |
<locale.h> |
Используется для смены кодировки. |
3.2 Задание
В программе необходимо реализовать функцию обработки элементов массива используя команды сравнения, переходов и циклов на встроенном ассемблере.
Результат целочисленный, возвращается из функции в регистре eax.
Массив передаётся в качестве параметра функции.
В программе реализовать вывод результата на экран.
В качестве комментария к каждой строке необходимо указать, какое действие выполняет команда относительно массива.
Найти количество элементов массива A={a[i]}, которые удовлетворяют условию: a[i] = 0.
3.3 Схема алгоритма
На рисунке 3.1 приведена схема алгоритма поиска нулевых элементов массива A. Для этого организовывается ввод с клавиатуры длины массива (size). Затем поэлементно заполняется массив (mas[ ]). Каждый i-тый элемент сравнивается с 0. Если элемент равен 0, то значение счетчика увеличивается на единицу, иначе цикл переходит к следующему элементу (i + 1). В качестве результата на экран выводится значение счетчика.
Рисунок 3.1 – Схема алгоритма подсчета нулевых элементов массива
3.4 Решение
#include "stdafx.h"
#include <stdio.h> // стандартный ввод/вывод
#include <iostream> // потоковый ввод/вывод
#include <locale.h>
// В одномерном массиве A={a[i]} целых чисел вычислить количество нулевых элементов;
int massiv(int mas[], int razmer)
{
int result = 0;
__asm{
xor esi , esi ; подготовим регистр индекса в массиве
xor edi , edi ; счётчик количества элементов
mov ebx , mas ; ebx указывает на начало массива
mov ecx , razmer ; счётчик цикла по всем элементам массива
mov edx , 0 ; подготовка для сравнения с 0
jcxz exit_1 ; завершить если длина массива 0
begin_loop:
mov eax , [ebx + esi*4] ; определяем текущий элемент
cmp eax , edx ; равнение mas[i] и 0
jne end_loop ; если не равно нулю, то конец цикла
inc edi ; элемент удовлетворяет условию, увеличиваем счётчик
end_loop:
inc esi ; переходим к следующему элементу
loop begin_loop ; повторяем цикл для всех элементов массива
exit_1: mov result , edi ; возвращаем количество элементов
}
return result ; // возвращаем результат вычисления выражения
}
int cmassiv(int mas[], int razmer)
{
int k = 0;
for (int j=0; j<razmer; j++)
{
if(mas[j] == 0) k++;
}
return (k);
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_CTYPE,"rus");
printf("Лабораторная работа№3\n");
printf("Вариант: 3\n");
printf("Автор: Галанова Дарья\n");
printf("Группа: 6113\n");
printf("Задание:\n");
printf("В одномерном массиве целых чисел вычислить количество нулевых элементов\n\n");
int size;
do{
std::cout << "Введите размер массива не больше 50: " << std::endl;// потоковый вывод
std::cin >> size;// потоковый ввод
}while(size>50|| size<0);
printf("\nВведите массив: \n");// стандартный вывод
int mas[50];
for (int i = 0; i< size; i++) // цикл для ввода массива
{
std::cin>>mas[i];// потоковый ввод
}
int res = massiv(mas, size);// вычисление выражения
printf("\n\nКоличество нулей: ");// стандартный вывод
printf("\nАссемблер: ");
printf("%d", res);// вывод результата вычисления выражения
printf("\nC++: ");
printf("%d", cmassiv(mas,size));
printf("\n");// стандартный вывод
system("PAUSE");
return 0;
}
3.5 Ответ
На рисунке 3.2 приведен тестовый пример выполнения программы при вводе корректных данных. На рисунке 3.3 приведен результат работы программы в случае ввода недопустимых значений (например, ввод отрицательной длины массива). Программа выполняет проверку на корректность и выдает предупредительное сообщение.
Рисунок
2.2 − Работа программы в случае корректного
ввода длины массива
Рисунок
2.3 − Работа программы при попытке ввода
некорректной длины массива
Лабораторная работа 4 «Изучение работы математического сопроцессора в среде Assembler»
4.1 Теоретические основы лабораторной работы
Команды, использованные в программе, приведены в таблице 4.1.
Таблица 4.1 Описание команд
Команда |
Назначение |
FINIT |
Инструкция инициализации сопроцессора. |
FSTSW |
Сохраняет текущее значение регистра SR в приемник. |
SAHF |
Загружает флаги из регистра AH. |
FTST |
Сравнивает текущее значение с нулем. |
FLD |
Загружает из памяти в вершину стека вещественное число. |
FILD |
Загружает из памяти в вершину стека ST(0) целое число. |
FSTP |
Извлекает из вершины стека ST(0) в память вещественное число. |
FADDP |
Сложение с «выбросом» результата в стек. |
FSUBP |
Вычитание с «выбросом» результата в стек. |
FMUL |
Умножение. |
FMULP |
Умножение с «выбросом» результата в стек. |
FDIV |
Деление. |
FDIVP |
Деление с «выбросом» результата в стек. |
JA |
Инструкция условного перехода «перейти, если больше чем…» |
JB |
Инструкция условного перехода «перейти, если меньше чем…» |
JE |
Инструкция условного перехода «перейти, если равно». |
JMP |
Используется в программе для организации безусловного перехода. |
MOV |
Команда пересылки данных (из источника в приемник). |
FCOM |
Сравнивает два операнда. |
FLDZ |
Поместить в стек +0,0 |
Использованные в программе библиотеки приведены в таблице 4.2.
Таблица 4.2 Описание библиотек
Библиотека |
Назначение |
"stdafx.h" |
Служит для генерации файла предкомпилированных заголовков; в него включено большинство стандартных и используемых в каждом приложении включаемых файлов. Сделано это для того, чтобы ускорить компиляцию проекта. |
<stdio.h> |
Используется для организации стандартного ввода/вывода. |
<iostream> |
Используется для организации потокового ввода/вывода. |
<locale.h> |
Используется для смены кодировки. |
4.2 Задание
В программе необходимо реализовать функцию вычисления заданного условного выражения на языке ассемблера с использованием команд арифметического сопроцессора.
Значения переменных передаются в качестве параметров функции.
В программе реализовать вывод результата на экран.
Все параметры функции имеют тип double.
Проверку деления на 0 реализовать также на встроенном ассемблере.
В качестве комментария к каждой строке необходимо указать, какой промежуточный результат, в каком регистре формируется.
В качестве комментария к строкам, содержащим команды сопроцессора необходимо указать состояние регистров сопроцессора.
Результат можно возвращать из функции в вершине стека сопроцессора.
4.3 Схема алгоритма
Рисунок
4.1 – Схема алгоритма вычисления исходного
выражения
На рисунке 4.1 приведена схема алгоритма вычисления функции
Для того чтобы вычислить результат необходимо организовать ввод с клавиатуры исходных данных (параметров a, b). После ввода сравниваются значения введенных параметров. Если a>b, то результат есть значение функции (b/a+5), если a<b, то результат есть значение функции ((a*a-b)/b), иначе результат равен -5.
4.4 Решение
#include "stdafx.h"
#include <stdio.h> // стандартный ввод/вывод
#include <iostream> // потоковый ввод/вывод
#include <locale.h>
// функция вычисления выражения ((b/a)+5 [a>b]; -5 [a=b]; (a*a-b)/b [a<b]);
bool error = 0;
double func(double a, double b)
{
double res; int status; const int c5=-5;
__asm{
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 c5 ; -5 a b
jmp endcalc
a_bigger: ftst ; сравнение a с 0
fstsw status ; сохраняем регистр флагов сопроцессора
mov ah, byte ptr [status+1]
sahf ; записываем в регистр флагов процессора
je err ; переход если a=0
fdivp st(1), st ; b/a
fild c5 ; 5 b/a
fsubp st(1), st ; b/a+5
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 err ; переход если b=0
fld st ; a a b
fmulp st(1), st ; a a*a b
fld st(1) ; b a*a b
fsubp st(1), st ; a*a-b b
fdivrp st(1), st ; (a*a-b)/b
jmp endcalc
err: mov error, 1 ; ввод ошибки
endcalc: fstp res ; сохранение результата
}
return res;
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_CTYPE,"rus");
printf("Лабораторная работа№4\n");
printf("Вариант: 3\n");
printf("Автор: Галанова Дарья\n");
printf("Группа: 6113\n");
printf("Задание:\n");
printf("Вычисление выражения с помощью сопроцессора.\n Условие:\n\n [a>b]\t(b/a)+5;\n [a=b]\t-5;\n [a<b]\t(a*a-b)/b\n\n");
double a, b;
printf("Введите a: \n");// стандартный вывод
std::cin >> a;// потоковый ввод
printf("Введите b: \n");// стандартный вывод
std::cin >> b;// потоковый ввод
double res = func(a, b);// вычисление выражения
if(error != 1)
{
if(a>b)
{
std::cout<<"\nРезультат С++ : [a>b] \t "<< (b/a)+5 << std::endl;
}
else{
if(a<b){
std::cout<<"\nРезультат С++ : [a<b] \t "<< (a*a-b)/b << std::endl;
}
else{
std::cout<<"\nРезультат С++ : [a=b] \t "<< -5 << std::endl;
}
}
std::cout<<"\nРезультат на ассемблере: "<< res << std::endl;
}
else{
std::cout<<"\nОшибка!"<<std::endl;
}
system("PAUSE");
return 0;
}
4.5 Ответ
На рисунках 4.2, 4.3, 4.4 приведены тестовые примеры выполнения программы при вводе корректных исходных данных. На рисунке 4.5 приведен результат работы программы в случае ввода недопустимых значений, когда делитель равен 0. Программа выполняет проверку данного значения и выдает предупредительное сообщение.
Рисунок
4.2 − Работа программы в случае a>b
Рисунок
4.3 − Работа программы в случае a=b
Рисунок
4.4 − Работа программы в случае a<b
Рисунок
4.5 − Работа программы в случае некорректного
ввода данных
Лабораторная работа 5 «Команды нахождения тригонометрических функций с помощью математического сопроцессора»
5.1 Теоретические основы лабораторной работы
Команды, использованные в программе, приведены в таблице 5.1.
Таблица 5.1 Описание команд
Команда |
Назначение |
FINIT |
Инструкция инициализации сопроцессора. |
FLD |
Загружает из памяти в вершину стека ST(0) вещественное число. |
FSIN |
Вычисление значения синуса ST(0). |
FSUBP |
Вычитание с «выбросом» результата в стек. |
Использованные в программе библиотеки приведены в таблице 5.2.
Таблица 5.2 Описание библиотек
Библиотека |
Назначение |
"stdafx.h" |
Служит для генерации файла предкомпилированных заголовков; в него включено большинство стандартных и используемых в каждом приложении включаемых файлов. Сделано это для того, чтобы ускорить компиляцию проекта. |
<stdio.h> |
Используется для организации стандартного ввода/вывода. |
<iostream> |
Используется для организации потокового ввода/вывода. |
<locale.h> |
Используется для смены кодировки. |
5.2 Задание
В программе необходимо реализовать функцию f(x)=xsinx, зависящую от аргумента x на языке ассемблера с использованием команд арифметического сопроцессора.
Значения переменных передаются в качестве параметров функции.
Составить таблицу значений функции на отрезке [π, π] с шагом h=0,1.
Номер вычисления №, значения x и f(x) вывести на экран.
Все параметры функции имеют тип double.
В качестве комментария к каждой строке необходимо указать, какой промежуточный результат, в каком регистре формируется.
В качестве комментария к строкам, содержащим команды сопроцессора необходимо указать состояние регистров сопроцессора.
Результат можно возвращать из функции в вершине стека сопроцессора.
5.3 Схема алгоритма
На рисунке 5.1 приведена схема алгоритма вычисления функции y=xsinx. Значение параметра x поступает из цикла основной программы. Далее производится пошаговое вычисление значения выражения.
Рисунок 5.1 – Схема алгоритма вычисления выражения y=xsinx.
5.4 Решение
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <locale.h>
#include <math.h>
#define PI 3.14159265
double funcasm(double x)
{
_asm
{
finit;
fld x ;x
fld st ;x x
fsin ;sinx x
fsubp st(1), st ;x - sinx
}
}
double funccpp(double x)
{
return(x - sin(x));
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL,"RUSSIAN");
printf("Лабораторная работа№5");
printf("Вариант: 3");
printf("Автор: Галанова Дарья");
printf("Группа: 6113");
printf("\n");
printf("Задание:");
printf("\n");
printf("Функция:y = x - sin(x)\nОтрезок:[-pi,pi]\nШаг:0,1");
printf("\n");
printf("\t\t\t\tТАБЛИЦА ОТВЕТОВ");
printf("\n");
printf("\n");
double h =0.1;
int i = 0;
double x = -PI;
printf("==================================================================\n");
std::cout<<" "<<" № "<<"\t\t"<<" x "<<"\t\t"<<" АССЕМБЛЕР"<<"\t\t"<<"C++";
printf("\n");
printf("==================================================================\n");
while((x >= -PI)&&(x <= PI))
{
printf(" %d \t\t% 0.1f \t\t % 0.4f \t\t% 0.4f",i + 1,x,funcasm(x),funccpp(x));
printf("\n");
x += h;
i++;
}
printf("\n");
printf("==================================================================\n\n\n");
system("PAUSE");
return 0;
}
5.5 Ответ
На рисунках 5.2, 5.3 приведен тестовый пример работы программы.
Рисунок
5.2 − Работа программы (вывод до 48 строки)
Рисунок
5.3 − Работа программы (вывод от 49 до 63
строки)
Лабораторная работа 6 «Нахождение суммы ряда с помощью математического сопроцессора»
6.1 Теоретические основы лабораторной работы
Команды, использованные в программе, приведены в таблице 6.1.
Таблица 6.1 Описание команд
Команда |
Назначение |
FINIT |
Инструкция инициализации сопроцессора. |
FSTSW |
Сохраняет текущее значение регистра SR в приемник. |
SAHF |
Загружает флаги из регистра AH. |
FLD |
Загружает из памяти в вершину стека ST(0) вещественное число. |
FLDZ |
Поместить в стек +0,0 |
FILD |
Загружает из памяти в вершину стека ST(0) целое число. |
FSTP |
Извлекает из вершины стека ST(0) в память вещественное число. |
FADDP |
Сложение с «выбросом» результата в стек. |
FMUL |
Умножение. |
FMULP |
Умножение с «выбросом» результата в стек. |
FDIVP |
Деление с «выбросом» результата в стек. |
FSIN |
Вычисление значения синуса ST(0). |
FXCH |
Обмен содержимым верхушки стека и численного регистра указанного в качестве оператора команды. |
FCOM |
Сравнивает два операнда. |
JL |
Инструкция условного перехода «перейти, если меньше чем». |
JG |
Инструкция условного перехода «перейти, если больше чем…» |
INC |
Увеличивает значение операнда в памяти или регистре на 1. |
MOV |
Команда пересылки данных (из источника в приемник). |
CMP |
Сравнивает два операнда. |
Использованные в программе библиотеки приведены в таблице 6.2.
Таблица 6.2 Описание библиотек
Библиотека |
Назначение |
"stdafx.h" |
Служит для генерации файла предкомпилированных заголовков. |
<stdio.h> |
Используется для организации стандартного ввода/вывода. |
<iostream> |
Используется для организации потокового ввода/вывода. |
<locale.h> |
Используется для смены кодировки. |
6.2 Задание
В программе необходимо реализовать функцию определения значения функции
, зависящей от аргумента x
на языке ассемблера с использованием
команд арифметического сопроцессора.Функция вычисляется в виде суммы ряда:
Вычисления прекращаются, если
,
где
– последующий член ряда;
- предыдущий член ряда. Кроме того, на
случай плохой сходимости следует
ограничить количество слагаемых сверху
некоторым наперёд заданным
,
т.е. выход их вычислительной процедуры
может произойти не по условию
,
а по условию
.
Значение функции и количество итераций
вывести для контроля на экран.Значение параметров x, ε и N передаются в качестве аргументов.
В программе необходимо также реализовать функцию вычисления значения элементарной функции на основе аналитического выражения, также с использованием команд арифметического сопроцессора. Значение функции вывести для контроля на экран.
Необходимо определить достигнутую погрешность, вычислив отклонение аналитического значения от вычисленного значения.
В качестве комментария к строкам содержащим команды сопроцессора необходимо указать состояние регистров сопроцессора.
6.3 Схема алгоритма
На рисунке 6.1 приведена схема алгоритма вычисления значения функции . Для того чтобы вычислить результат, необходимо организовать ввод с клавиатуры исходных данных (x, N, eps). Запускается цикл разложения в ряд : нахождение выражений (2k+1), sin(2k+1) и их частного, которое затем умножается на x. Условием выхода из цикла является превышение заданной погрешности текущего члена ряда, или превышение заранее заданного числа шагов(N) количеством итераций цикла. Результатом работы программы является значение суммы элементов.
Рисунок
6.1 – Схема алгоритма разложения в ряд
6.4 Решение
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <locale.h>
#include <math.h>
#define M_PI_4 0.785398163
double funcasm(double x, double eps, int N)
{
int status;int counter = -1; double otvet = 0;int const c2 =2; int const c1 =1;
_asm
{
mov ecx,N ; инициализация счётчика
finit ; инициализация сопроцессора
fld qword ptr[eps] ; eps
fld qword ptr[x] ; x eps
fldz ; sum=0 x eps
calc:
inc counter ; k++
fild counter ; k sum x eps
fild c2 ; 2 k sum x eps
fmulp st(1),st ; 2k sum x eps
fild c1 ; 1 2k sum x eps
faddp st(1), st ; 2k+1 sum x eps
fld st ; 2k+1 2k+1 sum x eps
fsin ;sin(2k+1) 2k+1 sum x eps
fxch st(1) ; 2k+1 sin(2k+1) sum x eps
fdivp st(1), st ;sin(2k+1)/2k+1 sum x eps
fmul st, st(2) ;xsin{2k+1)/2k+1 sum x eps
fcom st(4) ; сравниваем погрешность с текущим членом ряда
fstsw status ; сохраняем регистр флагов сопроцессора
mov ah, byte ptr [status+1]
sahf ; записываем в регистр флагов процессора
jl endcalc ; переход на конец, если достигли погрешность
faddp st(1),st ; sum+s x eps
cmp ecx, counter ; сравниваем достижение количества членов
jg calc ; переход на начало
endcalc:
fstp otvet ; сохранение результата sum
}
N = counter;
return otvet;
}
double analitic(double x)
{
double c4 = M_PI_4;
__asm{
finit ; подключение сопроцесора
fld x ; x
fld c4 ; pi/4 x
fmul st, st(1) ; pi/4 * x
}
}
double funccpp(double x)
{
return M_PI_4*x;
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL,"RUSSIAN");
printf("Лабораторная работа№6\n");
printf("Вариант: 3\n");
printf("Автор: Галанова Дарья\n");
printf("Группа: 6113\n");
printf("Задание:\nОпределение значения _pi/4 * x_\n\n");
double x;
double eps;
int N;
printf("\t\t\tВВОД ДАННЫХ\n\n");
double m = 0;
double n = 1;
printf("Введите значние _x_, принадлежащее промежутку [%f;%f],\nкол-во итераций и погрешность: \n\n",m,n);
do{
std::cout<<"Введите x: ";
std::cin >> x;
}while((x < m) || (x > n));
printf("\n");
do{
printf("Введите количество итераций: ");
std::cin >> N;
}while (N<1);
printf("\n");
do{
printf("Введите погрешность: ");
std::cin >> eps;
}while (eps>1 || eps <0);
printf("\n\n\n\t\t\tТАБЛИЦА ОТВЕТОВ\n\n");
printf("======================================================================\n");
std::cout<<" x "<<"\t"<<" АССЕМБЛЕР "<<"\t"<<" АССЕМБЛЕР2"<<"\t"<<" C++""\t"<<"ПОГРЕШНОСТЬ\n";
printf("======================================================================\n");
printf("% 0.3f \t% 0.7f \t% 0.7f \t% 0.7f \t% 0.7f",x,funcasm(x,eps,N),analitic(x),funccpp(x), abs(funcasm(x,eps,N)- analitic(x)));
printf("\n======================================================================\n\n");
system("PAUSE");
return 0;
}
6.5 Ответ
На рисунке 6.2 приведены тестовые примеры выполнения программы при вводе корректных исходных данных. На рисунке 6.3 приведен результат работы программы в случае попыток ввода некорректных значений. Программа выполняет проверку вводимых значений и дает шанс исправить некорректный параметр.
Рисунок
6.2 − Работа программы в случае верного
ввода исходных данных
Рисунок
6.3 − Работа программы при попытке ввода
некорректных данных
Список использованных источников
Зеленко, Л.С. Методические указания к лабораторной работе № 1 «Арифметические и логические команды в ассемблере» [Текст]/ Л.С. Зеленко, Д.С. Оплачко. – Самара: изд-во СГАУ, 2015. – 24 с.
Зеленко, Л.С.. Методические указания к лабораторной работе № 2 «Арифметические команды и операторы условного перехода» [Текст]/ Л.С. Зеленко, Д.С. Оплачко. – Самара: изд-во СГАУ, 2015. – 24 с.
ГОСТ 19.701-90 (ИСО 5807-85). ЕСПД. Схемы алгоритмов, программ, данных и систем. Условные обозначения и правила выполнения [Текст] ‑ Введ. 1990-01-01. – М.: Изд-во стандартов, 1991. 26 с.
Оплачко, Д.С. Методические указания к лабораторной работе № 3 «Работа с массивами и стеком на языке Assembler» [Текст]/ Д.С. Оплачко, Л.С. Зеленко. – Самара: изд-во СГАУ, 2012. – 19 с.
Оплачко, Д.С. Методические указания к лабораторной работе № 4 «Работа с математическим сопроцессором в среде Assembler» [Текст]/ Д.С. Оплачко, Л.С. Зеленко. – Самара: изд-во СГАУ, 2012. – 19 с.
СТО СГАУ 02068410-004-2007. Общие требования к учебным текстовым документам [Текст]: методические указания. Самара: Изд-во Самар. гос. аэрокосм. ун-та, 2007. 30 с.
