ПОСТАНОВКА И ФОРМУЛИРОВКА ЗАДАЧИ
ВВЕДЕНИЕ
Данная курсовая работа состоит в создании законченного программного продукта, выполняющего вычисление заданного количества значений функции вида y = f(x), в определённом интервале значений X. Количество значений (число интервалов разбиения) вводится пользователем с клавиатуры при поступлении соответствующего запроса. Максимальное число интервалов – 100. Программно проверяются введенные значение на соответствие тому или иному интервалу. Функция является разрывной и состоит из трёх частей, определённых на интервалах заданной величины. После вычисления значения Y заносятся в оперативную память последовательно, для каждого значения выделяется по 4 байта. Поиск нужного значения осуществляется путём задания величины смещения от начала таблицы (массива данных). Этот способ обеспечивает существенную экономию оперативной памяти (почти в два раза), так как не требует хранения соответствующих значений Х. После этого пользователю предлагается ввести значение X в определённом диапазоне значений. Далее, путём интерполирования, опираясь на заполненную структуру данных, производиться вычисление значения функции для введённого значения X. Результат вычисления выводиться на экран.
Программа написана на языке Assembler с использованием функций математического сопроцессора.
При разработке программы использовались следующие программные продукты:
1) Файловый и архивный менеджер FAR для написания кода программы.
2) Пакет Turbo Assembler 5.0 для трансляции и компоновки программы.
3) Microsoft Word, используемый для написания исходного кода программы.
ПОСТАНОВКА И ФОРМУЛИРОВКА ЗАДАЧИ
1.1 Задание на разработку программного продукта
Программа, которую необходимо разработать в процессе выполнения курсовой работы должна по полученной формульной зависимости вида сформировать программный продукт, который бы выполнял следующие функции:
В данной курсовой работе необходимо по полученной формульной зависимости вида сформировать программный продукт, который бы выполнял следующие функции:
– Запрашивал у пользователя количество участков разбиения интервала n;
- запрашивал у пользователя начальное значение и шаг изменения этого параметра ;
- производила вычисление значений функции для всех значений аргумента от = 15,9 до = 263
Первый интервал (x0 £ x£ x0+0.2l) y(x)=хsin(x)
Второй интервал (x0+0.2l< x£ x0+0.6l) y(x)=sin х2
Третий интервал (x0+0.6l< x£ xn) y(x)=х3
где l = xn - x0 –длина общего интервала;
- занесение пар значений х, у в структуру хранения данных;
- вывести на экран приглашения для ввода значения параметра х с указанием пределов варьирования;
- по введенному значению х вычислить функцию , опираясь на данные структуры путем интерполяции;
- вывести результат на экран в требуемом формате;
- запрос на повторение действий в формате «Y/N».
Программа должна быть оформлена с использованием процедур.
1.2 Формулирование требований к представлению исходных данных и выходных результатов.
Исходные данные и выходные результаты должны быть представлены в формате вещественных чисел с плавающей точкой. Для изображения чисел c плавающей точкой в сопроцессоре существует три формата данных. Короткий формат имеет 32 бита, а длинный 64 бита. Третий формат определяет 80-битовые числа. Сопроцессор использует такой формат "промежуточного действительного числа", чтобы обеспечить очень высокую точность для промежуточных результатов вычислений.
Целые числа — лучший способ представления многих величин. Целые числа просто понимать и использовать, а также легко преобразовывать в двоичное представление. Однако c целыми числами плохо работать в случае очень больших значений. Очень большое целое число обычно оканчивается длинной строкой нулей. Целые числа, кроме того, не способны представить значение, содержащее дробную часть, т. e. ЭВМ не может запомнить число 1/2 в целом представлении. Любые другие дроби, меньше 1, также невозможно представить, используя целые числа.
Ученые и математики давным-давно разработали способ представления этих чисел в достаточно удобном виде. На первом этапе вводится десятичная точка (.), которая будет показывать границу между целой и дробной частями числа. В случае целого числа позиция, представляющая единицы, всегда находится на правом краю числа; в случае, когда используется десятичная точка, цифры справа от нее представляют значения, меньше 1.
У целых чисел каждая позиция числа соответствует степени числа 10.
Десятичная точка показывает границу между позицией, соответствующей 100, и дробной частью. В дробной части позиции снова являются степенями числа 10, но теперь эти степени - отрицательные.
Поскольку каждая позиция десятичного числа отличается от соседней на степень числа 10, умножение числа на 10 эквивалентно сдвигу десятичной точки на одну позицию вправо. Аналогично деление на 10 сдвигает десятичную точку на позицию влево. Это свойство можно использовать для сдвига десятичной точки на соответствующее место: мы сдвигаем десятичную точку и одновременно корректируем число на ту же степень числа 10. Такое представление чисел называется представлением c плавающей точкой, поскольку десятичная точка "плавает" в числе; она больше не помечает абсолютное место между целой и дробной частями. Положение десятичной точки можно выбрать из соображений удобства, а затем умножить число на нужную степень числа 10, чтобы получить правильное значение.
Десятичное число c плавающей точкой состоит из двух частей. Значащая часть числа называется мантиссой. На практике мантисса обычно находится в пределах 1 < мантисса < 10. Другая часть числа c плавающей точкой - это порядок, степень, в которую нужно возвести число 10 перед умножением его на мантиссу, т. e. 9.3 х 107 имеет мантиссу 9.3 и порядок 7. Если основание системы счисления определено раз и навсегда, в нашем случае это 10, то для восстановления первоначального числа должны быть заданы только два числа — мантисса и порядок.
Двоичные числа c плавающей точкой изображаются аналогично десятичным; отличие заключается в том, что основание системы счисления здесь 2, а не 10. Мантисса имеет значения 1 < мантисса < 2, а порядок показывает степень числа 2
Для того чтобы сохранить максимальную точность, вычислительные машины почти всегда хранят мантиссу в нормализованном виде. Это означает, что мантисса есть число, лежащее между 1 и 2 (1 < мантисса < 2). Два соображения говорят в пользу нормализации. Во-первых, ни один незначащий 0 не дает никакого вклада в точность числа. (Это несправедливо для нулей, лежащих в конце числа; мы считаем, что число 1.000 более точно, чем число 1.0.) Если в мантиссе c плавающей точкой появились незначащие нули, точность числа падает. Во-вторых, способ хранения мантиссы числа c плавающей точкой подразумевает, что двоичная точка находится на фиксированном месте. Фактически подразумевается, что двоичная точка следует после первой двоичной цифры, т. e. нормализация мантиссы делает единичным первый бит, помещая тем самым значение мантиссы между 1 и 2. Для выполнения нормализации ЭВМ корректирует порядок числа на соответствующее значение.
Точно так же, как длина мантиссы числа определяет его точность, длина поля порядка определяет диапазон числа. Поле порядка содержит степень числа 2, и чем больше бит в этом поле, тем большее число может быть представлено.
Важно отметить, что, хотя диапазон и расширяется c увеличением числа бит порядка, точность не увеличивается. Значение порядка хранится не как значение число, представленное в дополнительном коде. Для упрощения вычислений значение порядка в ЭВМ хранится в виде смещенного числа. Это означает, что к действительному значению порядка прибавляется смещение перед записью его в память. Значение смещения выбрано так, чтобы допустить сравнение порядков. В частности, это полезно при сравнении двух чисел c плавающей точкой. Значения порядка и мантиссы записываются в одном элементе данных, причем порядок записывается перед мантиссой. В случае смещенного значения порядка программа может сравнивать числа побитно, начиная со старших позиций. Первое же неравенство показывает соотношение чисел, и больше не нужно учитывать никакие части чисел. Значение смещения определяется размером поля порядка.
1.3 Запись основных формул в формате ПОЛИЗ
Для того, чтобы написать программу для вычисления некоторого выражения, его необходимо предварительно преобразовать в удобный для программирования сопроцессора вид. Процесс преобразования напоминает подготовку выражения для метода трансляции, основанного на использовании обратной польской записи (ПОЛИЗ). Запись формул в формате ПОЛИЗ приведена в таблице 1.3.1.
Таблица 1.1.- Запись формул в формате ПОЛИЗ
Обычная формула
| Формат ПОЛИЗ
| xsinx
| XSINX **
| Sin(x^2)
| X ХSIN *
| Х3
| X Х X **
|
Использование польской записи в данном проекте обусловлено особенностью организации сопроцессора – хранением его операндов в стеке.
ПРОЕКТИРОВАНИЕ
Данный программный продукт написан на языке Turbo Assembler 5.0 с использованием команд математического сопроцессора. Математический сопроцессор представляет собой устройство, совмещённое в одном корпусе с основным процессором и предназначенное для выполнения операций над числами с плавающей точкой.
Программа написана в соответствии с принципами структурированного программирования. Это означает, что код программы состоит из нескольких модулей, выполняющих определённые действия, которые в свою очередь состоят из процедур, выполняющих определённые действия на уровне модуля.
2.1 Разработка алгоритма реализации задачи
Для расчета интерполяции необходимо ввести число N, необходимое для определения величины каждого интервала разбиения (dx).
Для всех N+1 точек расстояния необходимо провести вычисления значений функции. При этом необходимо проверять, какому из 3-х интервалов заданного диапазона принадлежит текущая точка Хi.
Значения Хi и соответствующие им значения функции Yi образуют таблицу значений функции. Сформированная таблица позволяет осуществлять вычисления аппроксимированных значений функции во всем интервале ее изменения от Х0 до Хn. При этом для введенного пользователем значения Х аппроксимация значения вычисляется по формуле .
1) Началом программы является метка Start модуля main
2) Инициализация сегмента данных и сопроцессора.
3) Сообщение с просьбой ввода чисел и с помощью процедуры ввода вещественного числа ввести количество интервалов и X.
4) Вычисление значений функций в соответствии с шагом dx ( количество значений – не больше 100)
5) Каждая итерация сопровождается вводом вещественного числа в массив.
6) Затем выполняется вывод результата в соответствии с вводимым
числом по формуле:
Данный программный продукт состоит из 3 – х программных кодов модулей, а именно:
1) main.asm
2) input.asm
3) out.asm
Рассмотрим каждый из модулей
1) В этом модуле находятся все необходимые процедуры, используемые для вычисления функций представленных в задании курсового проекта в соответствии с вариантом. Рассмотрим подробнее каждую из процедур:
Ssearch_Y proc– данная процедура определяет интервал попадания значения Х и вычисляет значения Y по одной из формул: xsin(x) - на первом участке диапазона значений х; sin(x^2) на втором участке диапазона; х3 – на третьем участке диапазона.
Search_l proc– данная процедура вычисляет значение длины интервала L =Хn - X0.
Search_vdX proc –процедура приращения значения аргумента dX=L/n.
Next_X proc-вычисляет следующее значение Х, т. е. Х=Х+dX.
2) Что касается этого файла, то здесь находятся программа вывода вещественного числа короткого формата (32 бита). Вход: выводимое значение - в поле float32. Выход: вывод вещественного числа короткого формата на экран.
3) В этом модуле находится функция Input_Float для преобразования введённых символов в вещественное число. Ввод с клавиатуры вещественного числа, максимальное число состоит из 20 цифр (22 - с учетом 0d0ah).Выход: вещественное число в вершине стека сопроцессора - эквивалент своего исходного символьного представления.
2.2 Разработка структуры программы в соответствии с выбранной моделью
Итак, из всего выше сказанного можно сделать вывод, что данный программный продукт можно разбить на 3 модуля, каждый из которых выполняет свои функции и процедуры, а именно:
main.asm содержит все необходимые процедуры, используемые для вычисления функций представленных в задании курсового проекта;
v_simvol.asm содержит программу вывода вещественного числа короткого формата (32 бита);
v_Vesh.asm содержит ввод с клавиатуры вещественного числа.
КОДИРОВАНИЕ
3.1 Уточнение структуры входных и выходных данных и определение ассемблерного формата их представления
Представим структуры входных и выходных данных в виде таблицы
Таблица входных и выходных данных приведена в приложении Б.
Таблица 3. 1. – Структуры входных и выходных данных
Модуль
| Имя переменной
| Значение
| Формат
| Main
| x0
| 6.0
| dd
| I1
| 24.6
| dd
| I2
| 80.4
| dd
| L
| 93.0
| dd
| Xn
| 99.0
| dd
| X
| 0.0
| dd
| Y
| 0.0
| dd
| n
| 150.0
| dd
| vdX
| 0.0
| dd
| Arrey
| 151 dup
| AR
| v_simvol
| a1
|
| dq
| pow_dec
|
| dw
| i_save
|
| dd
| f_save
| 0.0
| dq
| c_05
| 0.5
| dd
| c_10
| 10.0
| dd
| i_tol
|
| dw
| i_part
|
| dw
| f_part
|
| dt
| flag
|
| db
| m_sign
|
| db
| p_sign
|
| db
| string
| 20 dup<“ ”>
| db
| in_float
| NumTmp
|
| dw
| cn10
|
| dd
| cn48
|
| dd
|
3.2 Программирование задачи
Программная реализация данной задачи содержится в приложении А данного курсового проекта, где представлены листинги с соответствующими комментариями.
ОТЛАДКА И ТЕСТИРОВАНИЕ
4.1 Обнаружение, локализация и устранение ошибок в программе, выявленных в текстах
Отладка и тестирование производятся в отладчике, где при возникновении ошибки пользователь может отследить ее устранить в соответствии с установленными правилами синтаксиса языка Assembler.
Таблица 4.1. – Ошибки
Ошибка
| Вид ошибки
| Устранение
| Need expression
| FLD Arrey[si]
Синтаксическая ошибка
Не указано поле
| FLD Arrey[si].vX
| Illegal indexing mode
| mov eax,Arrey[si*8].vX
Ошибка адресации.
| mov eax,Arrey[si].vX
|
В программе возникали также незначительные синтаксические ошибки, которые не стоят внимательного рассмотрения.
Полученный программный продукт полностью соответствует поставленной задаче, хотя и не является идеальным, так как он не лишён многих недостатков. Вот некоторые из них:
1) Одним из недостатков данного программного продукта является необходимость явного указания того, что вводимое число является вещественным. Например, для ввода числа «2» необходимо ввести «2.0». Решением данной проблемы может быть изменение алгоритма преобразования числа, вводимого с клавиатуры, в его двоичный эквивалент.
2) Следующим недостатком является невысокая точность вычислений. Это связано с тем, что все вещественные числа в программе представлены в коротком (32 бита) формате. Для повышения точности вычисления необходимо использовать расширенный формат представления вещественных чисел (64 бита).
При тестировании определяли точность работы нашей программы и проводили с учётом зависимости погрешности значений от количества разбиений интервала.
Тестирование проводили путём изменения количества разбиений интервала и проверки полученного значения Y с помощью программы MathCAD.
По полученным данным (табл.4.1.2.-4.1.4.) построили графики зависимости погрешности значений от количества разбиений интервала (рис. 4.1.1.-4.1.3.). На графиках видно, что при увеличении количества разбиений интервала, погрешность уменьшается, значит программа работает верно.
Таблица 4.2.
1-й интервал
| | | Кол-во интервалов
| Полученное значение
| Введенное число
| Истинное значение
| Погрешность
|
| 0,35695029
|
|
| 42,780116
|
| 0,307754446
|
|
| 23,10177852
|
| 0,280413658
|
| 0,25
| 12,16546328
|
| 0,2633504037
|
|
| 5,34016148
|
| 0,2517427139
|
|
| 0,69708556
|
| 0,2514255034
|
|
| 0,570201356
|
Рис. 4.1. – График зависимости погрешностей на 1-ом интервале.
Таблица 4.3.
2-й интервал
| | | Кол-во интервалов
| Полученное значение
| Введенное число
| Истинное значение
| Погрешность
|
| 0,03780605
|
|
| 61,89780261
|
| 0,092
|
|
| 7,279333333
|
| 0,099283057
|
| 0,099222755
| -0,06077428
|
| 0,099312708
|
|
| -0,090657988
|
| 0,09924271
|
|
| -0,020111188
|
| 0,099313634
|
|
| -0,091590332
|
Рис. 4.2. – График зависимости погрешностей на 2-ом интервале.
Таблица 4.4.
3-й интервал
| | | | | Кол-во интервалов
| Полученное значение
| Введенное число
| Истинное значение
| Погрешность
|
| 0,159999642
|
|
| 0,00022375
|
| 0,159999642
|
|
| 0,00022375
|
| 0,159999642
|
| 0,16
| 0,00022375
|
| 0,159999642
|
|
| 0,00022375
|
| 0,159999642
|
|
| 0,00022375
|
| 0,159999642
|
|
| 0,00022375
|
Рис. 4.3. – График зависимости погрешностей на 3-ем интервале.
Список используемой литературы
1) В.И.Юров «Assembler». Учебник для вузов.2-е издание – СПб.:Питер,2004. – 637 с.: ил.
2) В.И.Юров «Практикум» - СПб.:Питер,2003. – 400 с.: ил
ПРИЛОЖЕНИЕ А
Программный код
Программный код модуля Main.asm
_windowout macro _str,_count ; макрос установки параметров экрана и вывода ;строки
xor ax,ax ;очищаем регистр для работы
mov ah,03h ;получить позицию курсора
mov bh,0 ;номер видеостраницы
int 10h ;вызов BIOS
mov ah,13h ;команда вывода строки
mov al,00000001b ; после вывода ? курсор в конец строки
xor bh,bh ;номер видеостраницы
mov cx,_count ;длина выводимой строки
mov bl,00001001b ;атрибут
push ds
pop es
mov bp,offset _str ; в базовую точку стека положить строку
int 10h
endm ; конец макроса
_massiv macro ;макрос добавления X,Y в массив.
xor ax,ax ;очистка ах
mov al,index ;в al index
mov dl,8 ;в dl 8
mul dl ;умножаем al(index) на 8, результат - в ах
mov si,ax ;в si index*8
mov eax,X ; помещаем текущее значение Х
mov A[si].vX,eax
mov eax,Y ; помещаем текущее значение У
mov A[si].vY,eax
inc index ; увеличиваем счетчик массива
endm
;-------------------------------------------------------------------------------
EXTRN Input_Float:FAR ;подключение внешних процедур
EXTRN Out_Float:FAR
include macro.inc ; подключение макроса для вывода строки
AR struc ;структура для хранения данных(X,Y)
vX dd 0
vY dd 0
AR ends
model SMALL
.586
stack 256
.data
mes_intro db 13,10,'Курсовая работа по СП. Выполнил ст. гр. СКС-08- ',13,10
len_i =$-mes_intro
mes1 db 13,10,'Введите число участков (5-100): N = $'
mes2 db 13,10,'Повторить? ... y/n $'
mes3 db 13,10,'Введите X от 15.9 до 400 : X = $'
mesY db 13,10,'Y = $'
mes_er db 13,10,'Ошибка ввода! Приложение будет завершено. OK $'
index db 0 ;текущий индекс в массиве
X0 dd 15.9 ;начальное значение X
i1 dd 92.72 ; граница первого интервала
i2 dd 246.36 ;граница второго интервала
Xn dd 400.0 ;конечное хначение Х
L dd 384.1 ;длинна всего интервала
X dd ? ;текущее значение X
Y dd ? ;текущее значение Y
n dd ? ;количество участков
vdX dd ? ;dX, размер участка
A AR 101 dup (<>) ;массив для хранения Х и У
s db 0
const_1 dd 100.0
const_6 dd 6.0
const_12 dd 1200.0
const_16 dd 0.16
.code
mov ah,s
mov ah,1
mov s,ah
Calc_1 proc ;процедура расчёта Y на 1-ом участке У = 100/X^2
finit ;инициализацизировать сопроцессор
fld const_1
fld X ;загрузить X в вершину стека
fmul x
fdiv
fstp Y ;получаем Y
ret
Calc_1 endp
Calc_2 proc ;процедура расчёта Y на 2-ом участке Y=1200/(X^2-6)
finit ;инициализация FPU
fld const_12 ;загрузить X в вершину стека
fld x
fmul x
fsub const_6
fdiv
fstp Y ;снять значение из стека, получить Y
ret ; возврат из процедуры
Calc_2 endp
Calc_3 proc ;процедура расчёта Y на 3-ом участке 0.16
finit ;инициализация сопроцессора
fld const_16
fstp Y ;получаем Y
ret
Calc_3 endp
next_X proc ; обработка значения
finit
fld X
fadd vdX ; добавить в массив
fstp X
ret
next_X endp
start:
mov ax,@data
mov ds,ax
_windowout mes_intro,len_i
;------------------------- начало основной программы ------------------------------
Out_Str mes1 ;вывод прилашения на ввод
call Input_Float ;ввод преобразованного n
FISTP n ;сохраняем n как целое
cmp n,5 ;проверка введённого числа
jl er ;окончание программы если n < 5
cmp n,100 ;проверка введённого числа
jg er ;окончание программы если n > 100
mov index,0 ;index=0
FINIT ;иниц. сопроцессора
FILD n ;ST(0) = n
FLD L ;ST(0) = L; ST(1) = n
FDIV ST(0),ST(1) ;ST(0) = L/n (dX)
FSTP vdX ;получаем dX
mov edx,X0 ;установка нач. зн X
mov X,edx ;
interval_1:
call Calc_1 ;вычисляем Y на 1-вом участке
mov eax,X
cmp eax,i1 ; проверяем на принадлежность интервалу
jg interval_2 ;если Х больше границы 1-го интервала переходим
;на interval_2
_massiv ;заносим данные в массив
call next_X ;вычисляем следующие знач. X
jmp interval_1 ;выч. следующее значение Y в этом интервале
interval_2:
call Calc_2 ;вычисляем Y на 2-ом участке
mov eax,X ;
cmp eax,i2 ;проверяем на принадлеж. интервалу
jg interval_3 ;если Х больше границы 2-го интервала переход
;на interval_3
_massiv ;заносим данные в массив
call next_X ;вычисляем следующие знач. X
jmp interval_2 ; выч. следующее значение Y в этом интервале
interval_3:
call Calc_3 ;вычисляем Y на 3-вом участке
mov eax,X ;
cmp eax,Xn ;сравнение
jg iter ;если Х больше границы 3-го интервала переход
;на end_calc
_massiv ;заносим данные в массив
call next_X ;вычисляем следующие знач. X
jmp interval_3 ; выч. следующее значение Y в этом интервале
iter:
Out_Str mes3
call input_float ; ввод преобразованного n
fstp X
mov eax,X ;проверка введённого X
cmp eax,X0
jl er ; если меньше ,то перейти на метку ?ошибка?
cmp eax,Xn
jg er ; если больше, то переход на метку
mov index,0
m_loop1: ;поиск в массиве второй точки для интерполяции
xor ax,ax ;очистка ах
mov al,index ;в al текщий индекс в массиве
mov dl,8 ;в dl 8
mul dl ;умножаем al на 8, результат в ах
mov si,ax ;в si index*8
inc index
mov eax,A[si].vX ;в eax значение X2
cmp eax,X
jng m_loop1 ; если не больше, то возобновить поиск второй точки для ;интерполяции
;A[si-8].vX - первая точка интерполяции(X1)
;A[si].vX - вторая точка интерполяции(X2)
FINIT ;интерполяция y(x)~=Y1+((Y2-Y1)/(X2-X1))*(X-X1)
FLD A[si].vX
FSUB A[si-8].vX ;ST(0)=X2-X1
FLD A[si].vY
FSUB A[si-8].vY ;ST(0)=Y2-Y1,ST(1)=X2-X1
FDIV ST(0),ST(1) ;ST(0)=(Y2-Y1)/(X2-X1)
FLD X ; ST(0)=х , ST(1)=(Y2-Y1)/(X2-X1)
FSUB A[si-8].vX ;ST(0)=(X-X1), ST(1)=(Y2-Y1)/(X2-X1)
FMUL ; перемножить
FADD A[si-8].vY ;в ST(0) результат
Out_Str mesY ; вывести сообщение
call Out_Float ; вызвать внешнюю процедуру преобразования результата
ENDPROG:;------------------ окончание -----------------------------------------
Out_Str mes2 ; вывести запрос на повторение операции
Get_Char ; получить введенный символ
cmp al,'y' ; сравнить с у
je iter ; если ? да, перейти на повторении операции
cmp al,'Y'
je iter
cmp al,'N'
je exit
cmp al,'n'
jne ENDPROG ; если - нет, перейти на окончание программы
exit: ; стандартный выход
mov ax,4c00h
int 21h
er:
Out_Str mes_er ; вывод сообщ об ошибке
Get_Char
mov ax,4c01h
int 21h
end start Программный код модуля OUT.asm
===Перевод вещественного числа в символьное представление===
;на входе – полученное в ходе выполнения расчетов вещественное число
;на выходе – переведенное в символьный формат число
;Перевод вещественного числа в символьное представление
masm
model use16 small
.586p
.stack 256h
PUBLIC Out_Float
.data
a1 dq 0
pow_dec dw 0
i_save dd 0
f_save dq 0.0
c_05 dd 0.5
c_10 dd 10.0
i_tol dw 10 ;точность представления дробной части
i_part dw 0
f_part dt 0
flag db 0
m_sign db 0 ;знак мантиссы
p_sign db 0 ;знак порядка
string db 20 dup(" ")
.code
Out_Float proc FAR
mov ax,@data
mov ds,ax
fstp a1
finit
fld a1 ;загрузка числа в st(0)
;-------проверка знака числа
ftst ;сравнение st(0) с нулем
fstsw ax ;сохранение слова состояния сопроцессора в ax
sahf ;отображение ah на регистр флагов
jnc posit_m ;если >= 0, то ничего не делать
fchs ;если меньше 0 - изменить знак
mov m_sign,1 ;установить флаг знака мантиссы
posit_m:
fxtract ;выделение мантиссы и порядка числа
;порядок в st(0), мантиссу в st(1)
fxch st(1) ;меняем знак мантиссы
;-------проверка знака порядка
ftst ;сравнение st(0) с нулем
fstsw ax ;сохранение слова состояния сопроцессора в ax
sahf ;отображение ah на регистр флагов
jnc posit_p ;если >= 0, не устанавливать флаг знака
mov p_sign,1 ;установить флаг знака порядка
posit_p:
fldlg2 ;загрузка в st(0) log10(2)
fmul ;переход от двоичного порядка к десятичному
fst f_save ;сохранение вещественного десятичного порядка
fsub c_05
fistp pow_dec ;сохранение целой части
;десятичного порядка
fld f_save ;восстанавливаем мантиссу в st(0)
fisub i_save
f2xm1 ;вычисление 2х-1
fld1 ;загрузить 1
fadd ;сложить
fild i_save ;результат загрузить в цел. Часть ч
fld1 ;загрузить 1
fscale ;выполнить масштабирование степени 2
fxch st(1)
fistp i_save
fmul
fmul
fcom c_10 ;сравнить мантиссу с 10
fstsw ax ;записать слово состояния сопроцессора в ах
sahf ;поместить в ah значение регистра флагов
jc m1 ;если десятичная мантисса меньше 10
;то не корректируем ее.
;------корректировка десятичной мантиссы
fidiv c_10
cmp p_sign,0 ;если порядок положительный
jz inc_pow ;то увеличиваем его на единицу
dec pow_dec ;в противном случае уменьшаем
jmp m1
inc_pow:
inc pow_dec
m1:
;------выделение целой части мантиссы
fst f_save ;пересылаем данные из st(0) в f_save
fsub c_05 ;округляем мантиссу до меньшего
;целого числа
fistp i_part ;и сохраняем
;------выделение дробной части мантиссы
fld f_save ;восстанавливаем мантиссу в st(0)
fisub i_part ;вычитаем целую часть
;------умножение дробной части на 10^i_tol
fldl2t ;в st(0) logе(10)
fimul i_tol
fst f_save ;промежуточно сохранение показателя степени
fsub c_05 ;округление до меньшего целого
fistp i_save ;и промежуточное сохранение
fld f_save ;сохраненное число в st(0)
fisub i_save ;определение дробной части показателя
f2xm1 ;возведение числа 2 в дробную часть степени
fld1 ;загрузка в st(0) числа 1
fadd ;корректировка результата на 1
fild i_save ;загрузка в st(0) целой части показателя ст.
fld1 ;в st(0) число 1
fscale ;возведени 2 в целую часть степени
fxch st(1) ;результат в st(1)
fistp i_save ;освобождение st(0)
fmul ;перемножение двух промежуточных результатов
fmul ;масштабирование дробной части мантиссы
;-------сохранение дробной части в BCD формате
fbstp f_part
mov di,0
;-------запись знака (в случае отрицательного числа)
cmp m_sign,0
jz setm ;если флаг знака =0, то обойти запись знака
mov string[di],"-"
inc di
;-------перевод мантиссы в символьную форму
setm:
mov al,byte ptr i_part
add al,30h
mov string[di],al
inc di
;-------добавление десятичной точки
mov string[di],"."
inc di
;-------перевод дробной части в символьную форму
mov si,9 ;указатель позиции на конец области памяти
mov cx,10 ;в счетчик цикла размер числового поля
cycl:
xor ax,ax ;очистка ax
mov al,byte ptr f_part[si] ;очередные две цифры числа в al
cmp al,0
jz m2
jmp m3
m2:
cmp flag,0
jz m4
m3:
ror ax,4
mov bl,al
add bl,30h
mov string[di],bl
inc di
shr ah,4
add ah,30h
mov string[di],ah
inc di
mov flag,1
m4:
dec si
loop cycl
;-------запись символа "Е"
mov string[di],"E"
inc di
;-------запись знака порядка(в случае отрицательного числа)
cmp p_sign,0
jz m5 ;если флаг знака =0, то порядок положителен
mov string[di],"-" ;записать в строку отрицательный знак порядка
mov ax,pow_dec ;и изменить знак порядка
not ax ;на положительный
add ax,1 ;для работоспособности
mov pow_dec,ax ;дальнейшего кода
jmp setpow
m5:
mov string[di],"+" ;записать в строку положительный знак порядка
;-------перевод порядка в символьную форму
setpow:
inc di ;продвинуть позицию в строке для записи
mov ax,word ptr pow_dec ;загрузить порядок в ax
mov bl,100
div bl ;выделение числа сотен в al
add al,30h ;перевод в ASCII код цифры
mov string[di],al ;запись символа в строку с результатом
inc di ;переход к следующему байту
mov pow_dec,ax ;дальнейшего кода
jmp setpow
m5:
mov string[di],"+" ;записать в строку положительный знак порядка
;-------перевод порядка в символьную форму
setpow:
inc di ;продвинуть позицию в строке для записи
mov ax,word ptr pow_dec ;загрузить порядок в ax
mov bl,100
div bl ;выделение числа сотен в al
add al,30h ;перевод в ASCII код цифры
mov string[di],al ;запись символа в строку с результатом
inc di ;переход к следующему байту
shr ax,8 ;остаток от деления в al
add al,30h ;перевод в ASCII код цифры
mov string[di],al ;запись символа в строку с результатом
inc di ;переход к следующему байту
mov string[di],"$" ;запись признака конца строки
mov ah,09h ;в al номер функции DOS вывода строки
mov dx,offset string ;запись признака конца строки
int 21h ;вывод строки на экран
ret
Out_Float endp
END
Программный код модуля INPUT.asm
;======= МОДУЛЬ ПРЕОБРАЗОВАНИЯ ВВЕДЁННЫХ СИМВОЛОВ В ВЕЩЕСТВЕННОЕ ЧИСЛО========
; на входе – введенные пользователем с клавиатуры символы, хранящиеся в буфере
; на выходе – преобразованные в двоичный посредством комплекса команд числа
include macro.inc
model SMALL
.586 ; 586 проц
stack 256 ; стек
PUBLIC Input_Float
inp_buf struc ; описание структуры буфера
len_buf db 22 ; длина буфера
len_in db 0 ; действительная длина введенной строки (без 0dh)
buf_in db 23 dup (20h) ; буфер для ввода (с учетом 0dh)
buf_end db 13,10,'$'
inp_buf ends
.data
inp_str inp_buf<>
NumTmp dw 0
cn10 dd 10.0
cn48 dd 48.0
.code
Input_Float PROC FAR
mov ax,@data
mov ds,ax
xor al,al
mov ah,0Ah
mov dx,offset inp_str
int 21h
cmp inp_str.len_in,0 ;проверка длинны строки на 0
je ER
xor cx,cx ;очистка сх
xor dx,dx
mov cl,inp_str.len_in ;в cl кoлич. введённых символов
mov si,0
FINIT ;инициализация FPU-сопроцессора
FLDZ ;затолкнуть 0 в FPU
m1:
mov dl,inp_str.buf_in[si]
cmp dl,"."
je m2
FMUL cn10 ;st(0) = st(0)*ST(2)
mov NumTmp,dx
FIADD NumTmp ;сложение ST(0),NumTmp
FSUB cn48 ;вычитание ST(0) = ST(0) - 48
inc si
loop m1
cmp cx,0
je Exit_proc
m2:
xor cx,cx
mov cl,inp_str.len_in
mov si,cx
FLDZ ;поместить в стек (FPU) 0
m3: ;преобразование дробной части
mov dl,inp_str.buf_in[si-1]
cmp dl,"."
je end_f
mov NumTmp,dx
FIADD NumTmp
FSUB cn48
FDIV cn10
dec si
jmp m3
end_f:
FADD ST(0),ST(1) ;сложение дробной и целой частей
;------------------------------ введённое число в ST(0)-------------------------
Exit_proc:
RET
ER:
FLDZ
RET
Input_Float ENDP
END
Программный код модуля macro.inc
;===============================================================
;Макрос настройки DS на сегмент данных.
;===============================================================
Init_DS MACRO
MOV AX,@DATA
MOV DS,AX
XOR AX,AX
ENDM
;===============================================================
;Макрос вывода строки на экран. String - выводимая строка.
;===============================================================
Out_Str MACRO String
PUSH AX
MOV AH,09h
MOV DX,OFFSET String
INT 21h
POP AX
ENDM
;===============================================================
;Макрос завершения работы программы.
;===============================================================
Exit_Prog MACRO
MOV AX,4C00h
INT 21h
ENDM
;===============================================================
;Макрос вывода числа на экран.
;===============================================================
Out_Number MACRO Num
PUSH AX
MOV DX,WORD PTR Num
ADD DX,30h
MOV AH,02h
INT 21h
POP AX
ENDM
;===============================================================
;Макрос ввода символа с клавиатуры.
;===============================================================
Get_Char MACRO Char
MOV AH,01h
INT 21h
ENDM
;===============================================================
;Макрос определения цвета текста.
;===============================================================
_windowout macro _string,_count
xor ax,ax
mov ah,03h ;в ah заносим номер функции
mov bh,0 ;заносим в bh номер видеостраницы
int 10h ;считать координаты курсора в dh,dl
mov ah,13h
mov al,00000001b
mov cx,_count
mov bl,00000010b ;color
push ds
pop es
mov bp,offset _string
int 10h
endm
;===============================================================
;Макрос добавления Х и У в массив.
;===============================================================
in_massive macro
xor ax,ax ;очистка ах
mov al,indxX ;в al indx
mov dl,8 ;в dl 8
mul dl ;умножаем al на 8, рез, в ах
mov si,ax ;в si indx*8
mov eax,X
mov Arrey[si].vX,eax
mov eax,Y
mov Arrey[si].vY,eax
inc indxX
endm
ПРИЛОЖЕНИЕ Б
Содержание
1. Общие сведения. 33
2. Функциональное назначение. 34
3. Описание логической структуры. 34
4. Вызов и загрузка программы. 39
5. Входные данные и выходные данные. 39
1. Общие сведения
Не нашли, что искали? Воспользуйтесь поиском по сайту:
©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.
|