Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты данной рассылки

Boriss
Статус: Академик
Рейтинг: 2544
∙ повысить рейтинг »
Абаянцев Юрий Леонидович aka Ayl
Статус: Профессионал
Рейтинг: 2035
∙ повысить рейтинг »
vladisslav
Статус: 7-й класс
Рейтинг: 1301
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Программирование / Assembler (Ассемблер)

Номер выпуска:1386
Дата выхода:24.11.2010, 04:00
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:223 / 67
Вопросов / ответов:1 / 1

Вопрос № 180887: Здравствуйте, уважаемые эксперты! Прошу Вас ответить на следующий вопрос: Ввести в консольном режиме два вещественных знаковых числа в виде строк. Ввод осуществить с помощью функции прерывания 21h. Перевести введенные строки в числа с осуществлени...



Вопрос № 180887:

Здравствуйте, уважаемые эксперты! Прошу Вас ответить на следующий вопрос:
Ввести в консольном режиме два вещественных знаковых числа в виде строк. Ввод осуществить с помощью функции прерывания 21h. Перевести введенные строки в числа с осуществление контроля корректности введенных значений. Числа представляют собой границы интервала, левая должна быть меньше правой.
В графическом режиме нарисовать график функции f(x)=sin x + sin 2x + sin 3x + sin 4x + sin 5x в пределах заданного ранее интервала. График необходимо отмасштабировать так, чтобы минимальное значение функции на заданном интервале помещалось на нижней строчке экрана, а максимальное на верхней.
Модель памяти SMALL
Среда выполнения: DOS 6.22 или выше
TASM 5.0

Отправлен: 22.11.2010, 10:40
Вопрос задал: katbka (Посетитель)
Всего ответов: 1
Страница вопроса »


Отвечает Лысков Игорь Витальевич (Старший модератор) :
Здравствуйте, katbka!
Вот такая получилась программа.
Думаю, разберетесь сами, программа достаточно прокомментирована.
Если что не будет ясно, обращайтесь в мини-форум.
Оси я все-таки нарисовал. Без них как-то неуютно
Код:

.model small, C ; модель памяти и порядок вызова параметров
.386
.data
sLeft db 'Enter left boundary: $' ;запрос левой границы
sRight db 0ah,'Enter right boundary: $' ;запрос правой границы

.data?
fLeft dq ? ;левая введенная граница (double)
fRight dq ? ;правая введенная граница (double)
fxDelta dq ? ;приращение по Х (double)
fyMax dq ? ;максим альное значение Y (double)
fyMin dq ? ;минимальное значение Y (double)
fyDelta dq ? ;приращение по Y (double)

sNum db ? ;буфер ля ввода числовой строки
sLen db ?
sString db 80 dup (?)

color_axis equ 0ddh ;цвет осей
color_graph equ 022h ;цвет графика

.code ;сегмент кода
.startup ;точка входа

lea dx, sLeft
mov ah, 9
int 21h ;приглашение для ввода левой границы

mov sNum, 80 ;максимальный размер
lea dx, sNum
mov ah, 0ah
int 21h ;вводим строку

lea si, sString ;введенная строка
lea di, fLeft ;сюда запишем
call StrToFloat ;преобразуем в double

Repeat: ;вводим правцую границу
lea dx, sRight
mov ah, 9
int 21h ;приглашение для ввода праой границы

lea dx, sNum
mov ah, 0ah
int 21h ;вводим строку

lea si, sString
lea di, fRight ;сюда запишем правую границу
call StrToFloat ;преобразуем в double

fld fLeft ;сравним границы
fld fRight ;левая должна быть меньше правой
fcompp ;сравниваем вещественные числа
fstsw ax
sahf
jbe Repeat ;иначе на повтор ввода правой границы

call CalcConsts ;посчитаем некоторые переменные

;рисуем график
mov ax, 0013h ;переходим в граф режим vga 320x200x256
int 10h

mov ax, 0a000h
mov es, ax ; es - сегмент видео

call PrintAxis ;рисуем оси
call PrintGraph ;рисуем график

finish:
mov ah, 0 ;ждем нажатия на клавишу
int 16h

mov ax, 0003h ;возвращаемся в текстовый режим
int 10h

mov ax, 4c00h ;выход
int 21h

PrintAxis proc ;рисуем оси
local x:word, y:word ;переменные
;рисуем ось абсцисс
fld fyMax ;макс Y = расстоянию от верха
fdiv fyDelta ;получаем число точек по вертикали
fistp y ;сохраняем номер строки
cmp y, 0 ;если за экраном, то не рисуем
jl PrintAxisY
cmp y, 199
jg PrintAxisY
call line, 0, y, 319, y, color_axis
PrintAx isY:
;рисуем ось ординат
fld fLeft
fchs ;(-1) * левый край = расстояние от левого края
fdiv fxDelta ;получаем число точек по горизонтали
fistp x ;сохраняем номер колонки
dec x ;x=x-1
cmp x, 0 ;если за экраном, то не рисуем
jl PrintAxisRet
cmp x, 319
jg PrintAxisRet
call line, x, 0, x, 199, color_axis
PrintAxisRet:
ret
PrintAxis endp

PrintGraph proc ;рисуем график
local x1:word, y1:word, x2:word, y2:word
mov x1, 0 ;начинаем с левого края
mov x2, 0
fld fLeft ;начинаем с x = fLeft
fld st ;сохраним для дальнейших вычислений
call fun ;y = f(x1)
fsubr fyMax ;растояние от верха
fdiv fyDelta ;в точках
fistp y1 ;y1 - строка первой точки
mov cx, 319 ;до конца строки
PrintPointsLoop: ;цикл рисования отрезков
inc x2 ;следующая точка на экране
fadd fxDelta ;добавляем дельту по X
fld st ;сохраним для дальнейших вычислений
call fun ;y = f(x2)
fsubr f yMax ;растояние от верха
fdiv fyDelta ;в точках
fistp y2 ;y2 - строка второй точки
;соединяем две точки отрезком
call li ne, x1, y1, x2, y2, color_graph
inc x1 ;сдвигаем первую точку
mov ax, y2
mov y1, ax
loop PrintPointsLoop ;по всей строке
fstp st ;уберем из стека сопроцессора сохраненную величину
ret
PrintGraph endp

CalcConsts proc ;посчитаем необходимые переменные
local iWork:word

;посчитаем приращение по X
fld fRight
fsub fLeft
mov cx, 319 ;число сравнений
mov iWork, cx
fidiv iWork
fstp fxDelta ;fxDelta = (fRight - fLeft) / 319

;найдем минимальное и максимальное Y
fld fLeft
fld st ;сохраним для дальнейших вычислений
call fun
fst fyMax ;пусть fyMax = f(x=fLeft)
fstp fyMin ;fyMin = f(x=fLeft)
SearchMinMaxLoop:
fadd fxDelta ;сдвигаем на приращение
fst ;сохраним
call fun
fcom fyMax ;сравним fyMax и f(x)
fstsw ax
sahf
jbe CmpMin ;если новый Y <= fyMax, то обходим
fst fyMax ;иначе сохраним, как fyMax
CmpMin:
fcom fyMin ;сравним с минимальным
fstsw ax
sahf
jae CmpNext
fst fyMin
CmpNext:
fstp st ;выкинем из стека значение функции
loop SearchMinMaxLoop;по всем
fstp st ;выкинем из стека и сохранненый X

;посчитаем приращение по Y
fld fyMax
fsub fyMin
mov iWork, 199
fidiv iWork
fstp fyDelta ;fyDelta = (fyMax - fyMin) / 199
ret
CalcConsts endp

StrToFloat proc ;преобразование строки в double
local Sign:word, Digit:word, C10:dword, Base:dword

mov Sign, 1 ;положительное число
mov C10, 10 ;будем умножать/делить на 10
mov Base, 10 ;делим цифру для дробной части
fldz ;начинаем с 0
xor cx, cx ;считаем точки
SearchStart: ;ищем начало числа
lodsb ;очередной символ
call CmpSep ;проверим на сепараторы
jc StrToFloatRet ;конец строки - на выход
jz SearchStart ;сепаратор - читаем следующий символ

cmp al, '-' ;проверим на минус
je NegativeNum ;отрицательное число
cmp al, '+& #39; ;можно записать + для положительного
je NextDigit ;на чтение следующего символа
jmp CmpDigit ;на проверку символа
NegativeNum:
mov Sign, -1 ;пометим знак

NextDigit: ;читаем следующий символ
lodsb
call CmpSep ;проверяем на сепаратор
jbe StrToFloatRet ;конец строки или сепараторы - на конец

CmpDigit: ;проверяем символ
cmp al, '.' ;десятичная точка
je Point
cmp al, ',' ;или запятая
je Point
cmp al, '0' ;проверим на цифры
jb StrToFloatRet ;на выход
cmp al, '9'
ja StrToFloatRet
and ax, 0fh ;превратим в число 0-0fh
mov Digit, ax ;сохраним для сопроцессора
jcxz PartInteger ;если целая часть
cmp cx, 9 ;для дробной части разрешаем 8 знаков после запятой
je StrToFloatRet
fild Digit ;введенную цифру
fidiv Base ;делим на 10^n, где n - позиция цифры
faddp ;и складываем с нашим числом
mov eax, Base ;n = n + 1
imul c10
mov Base, eax
inc cx ;считаем цифры после запятой
jmp NextDigit
PartInteger: ;целая часть
fimul c10 ;просто умножаем на 10
fiadd Digit ;и добавляем новую цифру
jmp NextDigit
Point: ;встретилась точка
test cx, cx
jnz StrToFloatRet ;уже была - на выход
inc cx ;помечаем, что пошла дробная часть
jmp NextDigit
StrToFloatRet: ;выход
fimul Sign ;учтем знак
fstp qword ptr [di] ;и сохраним в переменной
ret
StrToFloat endp

;FC = 1 - конец строки
;FZ = 1 - разделители
CmpSep proc ;проверка на разделитель
cmp al, 0dh
je CS_eol ;конец строки
cmp al, ' '
je CS_ret ;пробел
cmp al, 9
CS_ret: ;и табуляция
clc
ret
CS_eol:
stc
ret
CmpSep endp

;рисуем линию (x1,y1)-(x2,y2) цветом color
Line proc uses di bx cx, x1:word, y1:word, x2:word, y2:word, color:byte
local i:word, \ ;для работы со сопроцессором
delta_x:word, \ ;длина проекции на ось абсцисс
delta_y:word, \ ;длина проекции на ось ординат
incx:word, \ ;приращение по X
incy:word ;приращение по Y

;опре делим длину проекции на ось абсцисс и шаг по оси X
mov ax, x2
sub ax, x1 ;ax=x2-x1;

;определим шаг по X (+1 если вперед, -1 если назад, 0 если не меняется)
mov incx, 0 ;пусть incx=0
test ax, ax ;ax=delta_x
jz set_delta_x ;не меняется
jg set_x_1 ;вперед?
dec incx ;назад, значит incx=-1
neg ax ;найдем ax=abs(delta_x)
jmp set_delta_x ;на сохранение
set_x_1:
inc incx ;вперед, значит incx=1;
set_delta_x:
mov delta_x, ax ;delta_x = abs(x2-x1)

;определим длину проекции на ось ординат и шаг по оси Y
mov ax, y2
sub ax, y1 ;ax=y2-y1;

;определим шаг по Y (+1 если вперед, -1 если назад, 0 если не меняется)
mov incy, 0 ;пусть incy=0
test ax, ax ;ax=delta_y
jz set_delta_y ;не меняется
jg set_y_1 ;вперед?
dec incy ;назад, значит incy=-1
neg ax ;найдем ax==abs(delta_y)
jmp set_delta_y ;на сохранение
set_y_1:
inc incy ;вперед, значит incy=1;
set_delta_y:
mov delta_y, ax ;delta_y=abs(y2-y1)

;определим большее из проекций как основное напрвление
cmp ax, delta_x ;ax=delta_y
jge from_y ;y будет основным
cmp delta_x, 0 ;проверим, чтобы не было delta_x=0 (для точки),
jz Line_ret ; иначе будет деление на 0
;delta_x>delta_y && delta_x!=0
;основное направление - по оси X
fild delta_y
fidiv delta_x ;st=k=(float)(delta_y/delta_x)

;for (int i=0;i<delta_x;i++)
xor cx, cx ;cx=i
jmp cmp_i_x ;на проверку i<delta_x
x_loop: ;тело цикла
mov i, cx ;запишем переменную цикла в память (для сопроцессора)
fld st ;st=st(1)=k
fimul i ;st=k*i
fimul incy ;st=incy*k*i
call floor ;округлим до целого в большую сторону
fistp i ;сохраним в переменной
mov ax, i ;относительный номер строки на экране
add ax, y1 ;добавим до ординаты начальной точки
mov dx, 320 ;получим индекс начала строки экрана в сегменте экрана
imul dx ; для этого умножим на длину в байтах одной стоки
mov bx, ax ;сохраним bx=y=(y1+floor(incy*k*i))*320
;посчитаем X
mov ax, incx ;X меняется ровно на шаг приращения,
imul cx ; умноженному на индекс точки
add ax, x1 ;добавим абциссу начальной точки ax=x=x1+incx*i

add ax, bx ;сложим с индексом начала строки
mov di, ax ;будем адресовать через di

mov al, color ;цвет точки
mov es:[di], al ;рисуем!

inc cx ;на следующую точку
cmp_i_x:
cmp cx, delta_x ;дошли до конца?
jl x_loop
jmp Line_ret ;на выход

from_y: ;вдоль оси Y
fild delta_x
fidiv delta_y ;st=k=(float)(delta_x/delta_y)

;for (int i=0;i<delta_y;i++)
xor cx, cx ;cx=i
jmp cmp_i_y ;на проверку i<delta_y
y_loop: ;тело цикла
mov ax, incy ;Y меняется ровно на шаг приращения,
imul cx ; умноженному на индекс точки
add ax, y1 ;добавим абциссу начальной точки ax=y=y1+incy*i
mov dx, 320 ;получим индекс начала строки эк рана в сегменте экрана
imul dx ; для этого умножим на длину в байтах одной стоки
mov bx, ax ;сохраним bx=y=(y1+incy*i)*320
;посчитаем X
mov i, cx ;запишем переменную цикла в память (для сопроцессора)
fld st ;st=st(1)=k
fimul i ;st=k*i
fimul incx ;st=incx*k*i
call floor ;округлим до целого в большую сторону
fistp i ;сохраним в переменной
mov ax, i ;относительный номер строки на экране
add ax, x1 ;ax=x=x1+floor(incx*k*i)

add ax, bx ;сложим с индексом начала строки
mov di, ax ;будем адресовать через di

mov al, color ;цвет точки
mov es:[di], al ;рисуем!

inc cx ;на следующую точку
cmp_i_y:
cmp cx, delta_y ;дошли до конца?
jl y_loop
Line_ret:
fistp i ;удалим из сопроцессора k
ret
Line endp

;округление до целого в большую сторону
;округление по умолчанию, до ближайщего, не устраивает
floor proc
local CtrlWordOld:word, CtrlWordNew:word
fstcw Ctr lWordOld ;сохраним управляющее слово
fclex ;сбросим исключения
mov CtrlWordNew,0763h ;установим необходимое значение управляющ его слова
fldcw CtrlWordNew ;загружаем управляющее слово
frndint ;округляем st до целого
fclex ;сбросим исключения
fldcw CtrlWordOld ;восстановим старое управляющее слово
ret
floor endp

;f(x)=sin(x)+sin(2x)+sin(3x)+sin(4x)+sin(5x)
fun proc
local num:word
fld st
fsin
fxch
fld st
mov num, 2
fimul num
fsin
fxch
fld st
mov num, 3
fimul num
fsin
fxch
fld st
mov num, 4
fimul num
fsin
fxch
mov num, 5
fimul num
fsin
faddp
faddp
faddp
faddp
ret
fun endp

end

-----
Люби своего ближнего, как самого себя

Ответ отправил: Лысков Игорь Витальевич (Старший модератор)
Ответ отправлен: 23.11.2010, 02:54
Номер ответа: 264272
Украина, Кировоград
Тел.: +380957525051
ICQ # 234137952
Mail.ru-агент: igorlyskov@mail.ru

Вам помог ответ? Пожалуйста, поблагодарите эксперта за это!
Как сказать этому эксперту "спасибо"?
  • Отправить SMS #thank 264272 на номер 1151 (Россия) | Еще номера »
  • Отправить WebMoney:


  • Оценить выпуск »
    Нам очень важно Ваше мнение об этом выпуске рассылки!

    Задать вопрос экспертам этой рассылки »

    Скажите "спасибо" эксперту, который помог Вам!

    Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА
    на короткий номер 1151 (Россия)

    Номер ответа и конкретный текст СМС указан внизу каждого ответа.

    Полный список номеров »

    * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов)
    ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
    *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.


    © 2001-2010, Портал RFPRO.RU, Россия
    Авторское право: ООО "Мастер-Эксперт Про"
    Автор: Калашников О.А. | Программирование: Гладенюк А.Г.
    Хостинг: Компания "Московский хостер"
    Версия системы: 2010.6.23 от 23.11.2010

    В избранное