Хостинг портала RFpro.ru: Московский хостер Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64 РАССЫЛКИ ПОРТАЛА RFPRO.RU Лучшие эксперты данной рассылки Номер выпуска: | 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 (Россия) | Еще номера » | Оценить выпуск » Нам очень важно Ваше мнение об этом выпуске рассылки! Скажите "спасибо" эксперту, который помог Вам! Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА на короткий номер 1151 (Россия) Номер ответа и конкретный текст СМС указан внизу каждого ответа. Полный список номеров » * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов) ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются. *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании. |
Комментариев нет:
Отправить комментарий