Хостинг портала RFpro.ru: Московский хостер Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64 РАССЫЛКИ ПОРТАЛА RFPRO.RU Чемпионы рейтинга экспертов в этой рассылке Номер выпуска: | 1356 | Дата выхода: | 10.06.2010, 12:30 | Администратор рассылки: | Лысков Игорь Витальевич, Модератор | Подписчиков / экспертов: | 238 / 62 | Вопросов / ответов: | 4 / 5 | IRC-канал по теме: | #assembler | Вопрос № 178508: Доброго времени суток, уважаемые эксперты! Прошу помочь с такой задачей: необходима программа калькулятора, которая выполняет сложение, вычитание, умножение, деление, возведение в степень, извлечение корня. (можно в форме диалога). DOS, TASM.Заранее ... Вопрос № 178856: Здравствуйте, уважаемые эксперты. Помогите разобраться с реализацией алгоритма Брезенхейма в приведённой ниже процедуре. В Википедии алгоритм описан как увеличение X, при увеличении значения ошибки на величину наклона S, где S = Y1 - Y0/X1 - X0, т.е.... Вопрос № 178859: Здравствуйте уважаемые эксперты! У меня такой вопрос, точне нужна помощь. Задача такая вообщем, нужно реализовать на ассемблере программу, которая с клавиатуры 16-ричное двухзначное (восьмиразрядное) число, переводит его в 10-чное и 2-чное, а резул... Вопрос № 178862: Уважаемые эксперты! Помогите пожалуйста разработать программу на языке ASSEMBLER, вычисляющую значения функции F(x) в интервале [-10,12] при изменении переменной x шагом 2.<br><br> F(x) = a(x^2 + y^2 ) - b/(x^2 - y^2 ),<br> Вопрос № 178508: Доброго времени суток, уважаемые эксперты! Прошу помочь с такой задачей: необходима программа калькулятора, которая выполняет сложение, вычитание, умножение, деление, возведение в степень, извлечение корня. (можно в форме диалога). DOS, TASM.Заранее спасибо. Отправлен: 19.05.2010, 21:14 Вопрос задал: Виктор Никанорович, Посетитель Всего ответов: 1 Страница вопроса » Отвечает Лысков Игорь Витальевич, Модератор : Здравствуйте, Виктор Никанорович. Наконец, дошли руки и до Вашего калькулятора (надеюсь, что еще актуально)... Используются клавиши: Esc - выход c, BackSpace - вытирание =, Enter - расчет Tab - смена знака s - sqrt (квадратный корень) ^ - x*x (квадрат) Остальные понятно и так. Обратите внимание, что, если число не помещается на индикатор, то младшие цифры (возможно значащие) усекаются!!! Например, при возведении в квадрат или умножении... Обычно пишут "Error", я решил вот усекать...
Код: .model tiny, C
LenX equ 19 ;ширина окна калькулятора LenY equ 15 ;высота окна калькулятора StartX equ ((80-LenX)/2) ;столбец левого верхнего угла StartY equ ((25-LenY)/2) ;строка левого верхнего угла ;макро расчета смещения в видеобуфере по колонке и строке CALCPOS MACRO x,y mov al, y mov ah, 80 mul ah add ax, x shl ax, 1 ENDM
;макро вывода кнопки в позиции (x,y), со строкой title, цветом colkey ;в bx смещение начала окна калькулятора PRKEY MACRO x,y,title local TLoop CALCPOS x,y add ax, bx mov di, ax lea si, title mov ah, colkey mov cx, 3 TLoop: lodsb stosw loop TLoop ENDM
.code .286 .startup mov ax, 0003h ;необходимо под XP для прямого вывода int 10h ; в видеобуфер
call SaveScreen ;сохраним старое содержиое области экрана mov ax, 0b800h mov es, ax ;es - сегмент видеоданных call PrintFon ;рисуем фон калькулятора с рамкой call PrintKeys ;рисуем кнопки с индикатором ReWrite: ;сюда идем, когда надо перерисовать call PrintNum ;вывод числа на индикатор WaitKey: ;цикл ожидания нажатия на кнопку mov ah, 0 int 16h ;ж дем-с ;проверим код клавиши по двум таблицам: ;Keys1 - ASCII-коды, Keys2 - скан-коды push es ;сохраним адресацию видеобуфера push ds pop es ;es=ds lea di, Keys1 ;строка отрабатываемых кодов ASCII mov cx, LnKeys1 ;длина строки кодов ASCII repne scasb ;ищем jne CmpKeys2 ;не нашли - на поиск по второй таблице pop es ;восстановим сегмент видео sub di, (offset Keys1)+1 ;di - смещение в таблице кодов shl di, 1 ;будем адресовать слова call PgKeys1[di] ;отработаем! jnc ReWrite ;FC=0 - перерисовать jmp WaitKey ;иначе на ожидание клавиши
CmpKeys2: ;ищем по скан-кодам mov al, ah ;скан-код lea di, Keys2 ;строка отрабатываемых скан-кодов mov cx, LnKeys2 ;далее - аналогично предыдущему repne scasb pop es jne WaitKey
sub di, (offset Keys2)+1 shl di, 1 call PgKeys2[di] jnc ReWrite jmp WaitKey
PrintNum proc ;вывод числовой строки String на индикатор ;считаем п озицию индикатора на экране CALCPOS (StartX+2), (StartY+2) mov di, ax ;смещение в буфере экрана lea si, String ;строка ;найдем количество лидирующих нулей mov cx, LenX-5 ;всего sub cx, LenStr ;- длину выводимой строки mov al, ' ' jcxz PNSign ;если нисколько не надо PNSpaceLoop: stosb ;выведем лидирующи пробелы inc di loop PNSpaceLoop PNSign: ;выведем знак '-' или пробел mov al, 0dh ;код '-' = 2dh mul bSign ;al = 0dh (для 1) или 0 add al, ' ' ;получим или 2dh = '-', или 20h = ' ' stosb ;пишем inc di mov cx, LenStr ;число символов PNNumLoop: movsb ;копируем inc di ;пропускаем атрибуты loop PNNumLoop ret PrintNum endp
Exit proc ;выход call RestoreScreen ;востановим старое содержимое экрана mov ax, 4c00h int 21h Exit endp
BackSpace proc ;клавиша 'c' или backspace cmp fNew, 0 ;есл и в режиме ввода числа je BSContinue ; то на вытирание последнего символа mov LenStr, 1 ; иначе, пишем 0 mov word ptr String, '0' mov bSign, 0 ;сбросим знак mov fNew, 0 ;установим режим ввода числа mov PCount, 0 ;сбросим счетчик знаков после запятой clc ;на прорисовку ret BSContinue: ;вводим число mov bx, LenStr ;длина dec bx ;уменьшим на 1 mov String[bx], 0 ;затрем последний символ jnz BSSaveLen ;если больше чем 1 символ, то на сохр длины mov bSign, 0 ;сбросим знак mov String[bx], '0' ;зададим число 0 inc bx ;1 знак BSSaveLen: mov LenStr, bx ;сохраним длину cmp PCount, 0 ;если только целое, то на выход je BSRet dec PCount ;иначе уменьшим число знаков после точки BSRet: clc ;перерисовать ret BackSpace endp
Sqrt proc ;квадратный корень, вызывается кнопкой 's' call str2float ;преобразуем в вещественное число и в сопроцессор fsqrt ;корень call float2str ;преобразуем в строку String mov fNew, 1 ;признак нового числа clc ;перерисовать ret Sqrt endp
Square proc ;квадрат, вызывается кнопкой '^' call str2float fmul st, st(0) ;умножить на себя call float2str mov fNew, 1 clc ret Square endp
Oper proc ; / * - + mov Operation, di ;сохраним адрес операции mov fNew, 1 ;признак нового числа call str2float ;преобразуем первый операнд в вещественное число ret ; и в сопроцессор Oper endp
Equal proc ;закончить операцию, вызывается '=' или Enter-ом mov di, Operation ;тип операции cmp di, -1 ;Если не была задана операция, je Equal_None ; то не делаем ничего fld st ;st(1)=st call str2float ;преобразуем второй операнд в вещественное число ; и в сопроцессор call Function[di] ;выполнить call float2str ;преобразуем в строку String mov fNew, 1 ;признак нового числа mov Operation, -1 ;сбросим операцию clc ;перерисовать ret Equal_None: stc ;на ожидание клавиши ret Equal endp
Divide proc ;деление fdivp ret Divide endp
Multiply proc ;умножение fmulp ret Multiply endp
Substruct proc ;вычитание fsubp ret Substruct endp
Summa proc ;сумма faddp ret Summa endp
Sign proc ;смена знака cmp LenStr, 1 ;проверим на 0 jnz SignOk cmp String, '0' je NoSign ;для 0 не меняем SignOk: xor bSign, 1 ;меняем признак знака '-' clc ;перерисовать ret NoSign: stc ret Sign endp
Point proc ;точка cmp PCount,0 ;уже была введена? jne PointRet inc PCount ;инкремент позиции за точкой для следующей цифры jmp Digit ;дальше, как цифры PointRet: stc ;больше одной точки запрещено ret Point endp
;Цифры 0-9 Dig0: mov al,'0' jmp Digit Dig1: mov al,'1' jmp Digit Dig2: mov al,'2' jmp Digit Dig3: mov al,'3' jmp DigitDig4: mov al,'4' jmp Digit Dig5: mov al,'5' jmp Digit Dig6: mov al,'6' jmp Digit Dig7: mov al,'7' jmp Digit Dig8: mov al,'8' jmp Digit Dig9: mov al,'9' Digit: cmp fNew, 1 ;Если вводим новое число jne DigitContinue mov LenStr, 1 ;то сбрасываем его в 0 mov String, '0' mov bSign, 0 mov fNew, 0 mov PCount, 0 DigitContinue: ;иначе, вводим очередной разряд mov bx, LenStr ;проверим, есть ли место cmp bx, LenX-5 je NoInsert ;некуда писать! (14 позиций) cmp bx, 1 ;если один 0, то пишем вместо него jnz NotFirst cmp String, '0' jne NotFirst dec bx jmp SetFirst NotFirst: inc LenStr ;инкремент количества SetFirst: mov String[bx], al ;пишем в конец строки символ mov String[bx+1], 0 ;закрываем строк нулем clc ;перерисовать ret NoInsert: stc ;на ожидание кла виши ret
;Преобразование строки в вещественное число в st сопроцессора str2float proc ;преобразование строки в вещественное число local ww:word ;для загрузки в сопроцессор local dcount:word ;
fldz ;подготовим st=0 lea si, String ;числовая строка mov dcount, 0 ;число знаков после точки = 0 s2fNext: lodsb ;очередной символ cmp al, 0 ;дошли до конца? je s2fSign ;знак cmp al, '.' ;точка je s2fInc and ax, 0fh ;иначе готовим разряд mov ww, ax ; для загрузки в сопроцессор cmp dcount, 0 ;если целая часть, то je s2fMul10 ; на умножение на 10 mov cx, dcount ;иначе делим dcount раз на 10 fild ww ; очередной разряд s2fdiv: fidiv c10 ;делим dcount раз loop s2fdiv faddp ;складываем разряд за точкой с формируемым числом s2fInc: inc dcount ;для точки только увеличиваем dcount jmp s2fNext ;пока не дойдем до конца
s2fMul10: ;целое число fimul c10 ;умножаем старое на 10 fiadd ww ;и прибавляем очередной разряд jmp s2fNext s2fSign: cmp bSign, 0 ;если bSign == 1 je s2fRet fchs ;то меняем знак s2fRet: ret str2float endp
;преобразование вещественного числа из st в строку по адресу String float2str proc uses es ;сохраним es local dig:word ;буфер для извлечения целого из сопроцессора local sTemp:byte:64 ;временный буфер для строки push ds pop es ;es=ds
lea di, sTemp ;здесь будем формировать строку ftst ;Проверяем число fstsw ax ;флаги в ax sahf ;флаги в регистре флагов jnz f2s_notZero ;не 0 mov LenStr, 1 ;длина 1 mov bSign, 0 ;сбрасываем знак mov ax, '0' ;если 0, то выводим 0 stosw jmp f2s_Ret ;на выход
f2s_notZero: ;не 0 mov bSign, 0 ; пока считаем, что положительное jnc f2s_1 ;если оно отрицательное, mov bSign, 1 ; то помечаем минус fchs ; и оставляем модуль числа. ; Пояснение далее пойдёт на примере. ; ST(0) ST(1) ST(2) ST(3) ... ; Отделим целую часть от дробной. ; 73.25 ... что-то не наше f2 s_1: fld1 ; 1 73.25 ... fld st(1) ; 73.25 1 73.25 ... ; Остаток от деления на единицу даст дробную часть. fprem ; 0.25 1 73.25 ... ; Если вычесть её из исходного числа, получится целая часть. fsub st(2), st ; 0.25 1 73 ... fxch st(2) ; 73 1 0.25 ... ; Сначала поработаем с целой частью. Считать количество цифр будем в CX. xor cx, cx ; Поделим целую часть на десять, f2s_2: fidiv c10 ; 7.3 1 0.25 ... fxch st(1) ; 1 7.3 0.25 ... fld st(1) ; 7.3 1 7.3 0.25 ... ; отделим дробную часть - очередную справа цифру целой части исходного числа,- fprem ; 0.3 1 7.3 0.25 ... ; от чатсного оставим только целую часть fsub st(2), st ; 0.3 1 7 0.25 ... ; и сохраним цифру fimul c10 ; 3 1 7 0.25 ... fistp dig ; 1 7 0.25 ... inc cx ; в стеке. push dig fxch st(1) ; 7 1 0.25 ... ; Так будем повторять, пока от целой части не останется ноль. ftst fstsw ax sahf jnz f2s_2 ; Теперь выведем её. f2s_3: pop ax ; Вытаскиваем очередную цифру, переводим её в символ и выводим. add al, 30h stosb ; И так, пока не выведем все цифры. loop f2s_3 ; 0 1 0.25 ... ; Итак, теперь возьмёмся за дробную часть, для начала проверив её существование. fstp st(0) ; 1 0.25 ... fxch st(1) ; 0.25 1 ... ftst fstsw ax sahf jz f2s_5 ; Если она всё-таки ненулевая, выведем точку lea ax, sTemp mov cx, di sub cx, ax sub cx, 63 neg cx mov al, '.' stosb ; Помножим дробную часть на десять f2s_4: fimul c10 ; 2.5 1 ... fxch st(1) ; 1 2.5 ... fld st(1) ; 2.5 1 2.5 ... ; отделим целую часть - очередную слева цифру дробной части исходного числа,- fprem ; 0.5 1 2.5 ... ; оставим от произведения лишь дробную часть fsub st(2), st ; 0.5 1 2 ... fxch st(2) ; 2 1 0.5 ... ; сохраним полученную цифру во временной ячейке fistp dig ; 1 0.5 ... ; и сразу выведем. mov ax, dig add al, 30h stosb ; Теперь, если остаток дробной части ненулевой fxch st(1) ; 0.5 1 ... ftst fstsw ax sahf ; и мы вывели менее cx цифр, продолжим loopnz f2s_4 ; 0 1 ... ; Итак, число выведено. Осталось убрать мусор из стека. f2s_5: fstp st(0) ; 1 ... fstp st(0) ; ... mov byte ptr [di], 0 ; и скопировать в буфер String lea si, sTemp lea di, String mov LenStr, 0 ;длина f2s_6: lodsb stosb ;копируем 1 байт inc LenStr ;считаем cmp LenStr, 14 ;копируем только 14 байт !!! (если получится число ; с большим чем 14 байт знаков, то последние усекутся) je f2s_7 ;насильно закрываем нулем! cmp al, 0 jne f2s_6 ;копирование завершаем по 0 dec LenStr ;отнимем 1 (посчитался нулевой байт) f2s_7: mov byte ptr [di], 0 ;закроем нулем (для случая обрезания) f2s_Ret: ret float2str endp
;Вывод кнопок калькул ятора PrintKeys proc CALCPOS StartX, StartY ;позиция на экране mov bx, ax ;база (для макро) ;x,y,name ;надп. :клавиши : действие PRKEY 2, 4, key_c ;" c " : c, backspace : вытирание PRKEY 6, 4, key_sn ;"+/-" : Tab : знак PRKEY 10, 4, key_sq ;"sqr" : s : sqrt PRKEY 14, 4, key_st ;"x^2" : ^ : x*x PRKEY 2, 6, key_7 ;" 7 " : 7 : 7 PRKEY 6, 6, key_8 ;" 8 " : 8 : 8 PRKEY 10, 6, key_9 ;" 9 " : 9 : 9 PRKEY 14, 6, key_dv ;" / " : / : / PRKEY 2, 8, key_4 ;" 4 " : 4 : 4 PRKEY 6, 8, key_5 ;" 5 " : 5 : 5 PRKEY 10, 8, key_6 ;" 6 " : 6 : 6 PRKEY 14, 8, key_ml ;" * " : * : * PRKEY 2,10, key_1 ;" 1 " : 1 : 1 PRKEY 6,10, key_2 ;" 2 " : 2 : 2 PRKEY 10,10, key_3 ;" 3 " : 3 : 3 PRKEY 14,10, key_ms ;" - " : - : - PRKEY 2,12, key_0 ;" 0 " : 0 : 0 PRKEY 6,12, key_pt ;" . " : . : . PRKEY 10,12, key_eq ;" = " : =, Enter : посчитать PRKEY 14,12, key_pl ;" + " : + : + ;индикатор CALCPOS 2,2 add ax, bx mov di, ax mov ah, colscr mov al, ' ' mov cx, LenX-4 rep stosw
ret PrintKeys endp
;вывод фона с рамкой PrintFon proc CALCPOS StartX, StartY ;стартовая позиция mov di, ax mov ah, colfon ;цвет фона mov al, lu ;левый верхний угол stosw mov al, hor ;горизонтальная линия mov cx, LenX-2 rep stosw mov al, ru ;правый верхний угол stosw mov cx, LenY-2 ;число внутренних строк PFLoop: push cx add di, (80-LenX)*2 ;на следующую строку mov al, ver ;вертикальная черта stosw mov al, ' ' ;пробелы mov cx, LenX-2 rep stosw mov al, ver ;вертикальная черта stosw pop cx loop PF Loop add di, (80-LenX)*2 ;на последнюю строку mov al, ld ;левый нижний угол stosw mov al, hor ;горизонтальная линия mov cx, LenX-2 rep stosw mov al, rd ;правый нижний угол stosw ret PrintFon endp
SaveScreen proc ;сохраняем область экрана, куда будем выводить uses ds,si,di,cx,bx mov ah, 3 mov bh, 0 int 10h mov CursorForm, cx ;сохраним форму курсора
mov cx, 2000h mov ah, 1 int 10h ;скроем курсор
mov ax, 0b800h mov ds, ax ;копируем с экрана CALCPOS StartX, StartY mov si, ax lea di, OldScreen ;буфер для сохранения mov cx, LenY SaveRowLoop: push cx mov cx, LenX rep movsw pop cx add si, (80-LenX)*2 loop SaveRowLoop ret SaveScreen endp
RestoreScreen proc ;восстанавливаем область экрана uses si,di,cx ;аналогично, только в другую сторону CALCPOS StartX, StartY mov di, ax lea si, OldScreen mov cx, Le nY RestoreRowLoop: push cx mov cx, LenX rep movsw pop cx add di, (80-LenX)*2 loop RestoreRowLoop
mov cx , CursorForm ;восстанавливаем форму курсора mov ah, 1 int 10h ret RestoreScreen endp
.data ;символы псевдографики для рисования рамки lu db 0dah ru db 0bfh ld db 0c0h rd db 0d9h hor db 0c4h ver db 0b3h
;цвета colfon db 3bh ;цвет фона colkey db 17h ;цвет клавиш colscr db 71h ;цвет индикатора
;строки, выводимые на клавишах key_0 db ' 0 ' key_1 db ' 1 ' key_2 db ' 2 ' key_3 db ' 3 ' key_4 db ' 4 ' key_5 db ' 5 ' key_6 db ' 6 ' key_7 db ' 7 ' key_8 db ' 8 ' key_9 db ' 9 ' key_pt db ' . ' key_eq db ' = ' key_pl db ' + ' key_ms db ' - ' key_ml db ' x ' key_dv db ' / ' key_st db 'x^2' key_sq db 'sqr' key_c db ' c ' key_sn db '+/-'
;строка для поиска отрабатываемых клавиш (по ASCII) Ke ys1 db '/*-+^=.0123456789',8,1bh,9,0dh LnKeys1 equ $-Keys1 ;длина ;адреса подпрограмм отработки действий по клавишам PgKeys1 dw Oper,Oper,Oper,Oper,Square,Equal,Point dw Dig0,Dig1,Dig2,Dig3,Dig4,Dig5,Dig6,Dig7,Dig8,Dig9 dw BackSpace,Exit,Sign,Equal
;строка для поиска отрабатываемых клавиш (по скан-кодам) Keys2 db 2eh, 1fh LnKeys2 equ $-Keys2 PgKeys2 dw BackSpace, Sqrt
;таблица отработки функций /,*,-,+ Function dw Divide,Multiply,Substruct,Summa
;буфер, содержащий числовую строку для вывода на экран String db '0',14 dup (0)
;признак отрицательного числа 0/1 : -/+ bSign db 0
;длина строки String LenStr dw 1
c10 dw 10 ;константа 10 PCount dw 0 ;для контроля ввода точки fNew dw 0 ;признак нового числа Operation dw -1 ;тип операции для /,*,-,+, ; если не была указана операция, то -1
.data? CursorForm dw ? ;сохраняем форму курсора OldScreen dw LenY*LenX dup (?) ;буфер для сохранения фрагмента экрана, где рисуем калькулятор
end
----- Удачи! Ответ отправил: Лысков Игорь Витальевич, Модератор Ответ отправлен: 10.06.2010, 10:49 Номер ответа: 262047 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 262047 на номер 1151 (Россия) | Еще номера » | Вопрос № 178856: Здравствуйте, уважаемые эксперты. Помогите разобраться с реализацией алгоритма Брезенхейма в приведённой ниже процедуре. В Википедии алгоритм описан как увеличение X, при увеличении значения ошибки на величину наклона S, где S = Y1 - Y0/X1 - X0, т.е. как соотношение катетов. Если ошибка превысила 0.5, линия стала ближе к следующему Y, поэтому мы увеличиваем Y на единицу, одновременно уменьшая значение ошибки на 1. 1 В приведённой ниже процедуре из книги Кулакова мне непонятно, с какой целью делается умножение на 2 командой shl AX,1. 2 Для чего потом вычитается sub AX,[DeltaX]. Как-то странно получается: [DeltaY] увеличили в 2 раза, а [DeltaX] оставили без изменений. Величина наклона S изменилась же, а должна быть постоянной. В комментариях пишется, что командой sub AX,[DeltaX] определяется ошибка накопления, а в чём тут ошибка накопления, я не понимаю. 3 Потом ещё раз вычитается sub AX,[DeltaX] и заносится в [DeltaYx2MinusDeltaXx2]. Для чего эта уже вторая ошибка накопления? Разница между [ErrorTerm] и [DeltaYx2MinusDeltaXx2] очень большая. 4 В процедуре для вывода точки по X или Y значение ошибки сравнивается с 0 (cmp [ErrorTerm],0), а в Википедии говорится о сравнении с 0,5. Немножко посчитал, у меня дробных величин не получилось, все числа целые. Процедуру я немножко изменил: 32-битные регистры перевёл в 16. Отправлен: 04.06.2010, 16:16 Вопрос задал: Adsorores, Посетитель Всего ответов: 1 Страница вопроса » Отвечает Лысков Игорь Витальевич, Модератор : Здравствуйте, Adsorores. Если ответить коротко, то данные формулы - результат довольно длинных преобразований. Которые можете посмотреть, например, вот здесь, рассказано все очень подробно, со всеми выкладками. Приведена программа на С.
Попутно замечу. Подправьте pushad/popad на pusha/popa. И в одном месте остался edx ----- Удачи! Ответ отправил: Лысков Игорь Витальевич, Модератор Ответ отправлен: 05.06.2010, 01:58 Номер ответа: 261890 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Оценка ответа: 5 Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261890 на номер 1151 (Россия) | Еще номера » | Вопрос № 178859: Здравствуйте уважаемые эксперты! У меня такой вопрос, точне нужна помощь. Задача такая вообщем, нужно реализовать на ассемблере программу, которая с клавиатуры 16-ричное двухзначное (восьмиразрядное) число, переводит его в 10-чное и 2-чное, а результат выводить на экран. Помогите пожалуйста. Я тут собрал из частей код но не смог оптимизировать Отправлен: 04.06.2010, 19:06 Вопрос задал: Артем Борисовский, Посетитель Всего ответов: 2 Страница вопроса » Отвечает amnick, Студент : Здравствуйте, Артем Борисовский.
В приложении - исправленная программа. Замечания помечены ;! Ваша программа рассчитана не только на 2-значные, но и на 16-ричные числа до 4-х значащих цифр. Буквы должны быть в верхнем регистре. Преобразование в 10-тичную и 2-ичную системы правильное, но слишком маленькие буфера для результатов. Кроме того, перед преобразованием в 2-ичную систему число уже было утеряно. Чуток поправил сообщения.
Работу программы проверил.
Успехов! Приложение: Ответ отправил: amnick, Студент Ответ отправлен: 04.06.2010, 22:29 Номер ответа: 261886 Оценка ответа: 5 Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261886 на номер 1151 (Россия) | Еще номера » | Отвечает Лысков Игорь Витальевич, Модератор : Здравствуйте, Артем Борисовский. Моя версия подправленной программы. Вводит 1 байт, не более 2 hex-цифр из командной строки. Добавил проверку на ошибки: проверяются символы на корректность, число цифр Поменял вывод десятичного числа.
Код: cod segment assume cs:cod,ds:cod org 100h begin: mov dx,offset Start call Message ;Чтение из командной строки mov bx,80h ; получение длины xor cx,cx mov cl,[bx] jcxz ErrorNoCmd ;проверим на ноль - ничего не задано ; вставлем число в регистр dx dec cx cmp cx,2 ;ждем 1 или 2 hex цифры! ja ErrorBigCmd ;если больше, то ошибка lea si,[bx+2] xor dx,dx PutNumbToDX: ; вставляем число в регистр dx shl dx,4 lodsb or al,20h ;чтобы б уковки 'a' и 'A' стали одинаковыми - 'a' ;на цифры не влияет! sub al,'0' jc ErrorNum ;<'0' - ошибка cmp al,9 jbe TransDone ;'0'-'9' - ok sub al,('a'-'0')-10 jc ErrorNum ;'9'-'a' - ошибка cmp al,0fh ja ErrorNum ;>'f' - ошибка TransDone: or dl,al loop PutNumbToDX
;Конвертируем в десятичную и выводим на экран push dx mov dx,offset ResPrompt call Message pop ax ;в ax число mov bx,10 ;будем делить на 10 mov di,offset Symbols ;буфер для числовой строки xor cx,cx ;будем считать push ax ;сохраним для дальнейшего преобразования в двоичный код GetDigit: ;процедура перевода в десятичную СС xor dx,dx div bx ;остаток - очередная младшая цифра push dx ;сохраним в стеке inc cx ;считаем test ax,ax ;пока что-то есть jnz GetDigit PutDigit: ;выводим в обратном поряд ке pop ax add al,'0' stosb loop PutDigit ;по всем цифрам call PrintNum ;дооформим строку и выведем ; Конвертируем в двоичную и выводим на экран mov dx,offset ResPromptBin call Message pop dx ;наше число mov cx,8 ;8 бит mov di,offset Symbols ;в том же буфере GetBin: ; процедура перевода в двоичную СС xor ax,ax shl dl,1 ;у нас байт, с ним и работаем adc al,'0' stosb loop GetBin mov al,'b' ;добавим в конце 'b' stosb call PrintNum ;дооформим строку и выведем Exit: ; Выход mov dx,offset Finish jmp Message
;ошибки ErrorNoCmd: ;без параметра mov dx,offset NoCmd jmp Message ErrorNum: mov dx,offset ErrNum;не hex-число jmp Message ErrorBigCmd: mov dx,offset BigCmd;больше 2-х цифр jmp Message PrintNum: ;вывод числовой строки mov ax,0d0ah ;добавим перевод строки stosw mov al,'$' ;добавим '$& #39; для функции 9 stosb mov dx,offset Symbols Message: ;процедура вывода на экран mov ah,09h int 21h retn
Start db 'Start !',0ah,0dh,'$' NoCmd db 'No specified symbols in CMD !',0ah,0dh,'$' BigCmd db 'Many symbols in CMD! Must be two symbols',0ah,0dh,'$' ErrNum db 'Not hex number!',0ah,0dh,'$' ResPrompt db 'Result in digit: ','$' ResPromptBin db 'Result in bin: ','$' Symbols db 16 dup (?) Finish db 'Finish!',0ah,0dh,'$'
cod ends end begin
----- Удачи! Ответ отправил: Лысков Игорь Витальевич, Модератор Ответ отправлен: 05.06.2010, 00:08 Номер ответа: 261888 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261888 на номер 1151 (Россия) | Еще номера » | Вопрос № 178862: Уважаемые эксперты! Помогите пожалуйста разработать программу на языке ASSEMBLER, вычисляющую значения функции F(x) в интервале [-10,12] при изменении переменной x шагом 2.<br><br>
F(x) = a(x^2 + y^2 ) - b/(x^2 - y^2 ),<br> где a = -2.5; b = 0.563; y=4 Отправлен: 05.06.2010, 02:31 Вопрос задал: Лисневская Мария Геннадьевна, Посетитель Всего ответов: 1 Страница вопроса » Отвечает Лысков Игорь Витальевич, Модератор : Здравствуйте, Лисневская Мария Геннадьевна. Примерно так:Код: ;Программа вычисляет значения функции F(x) в интервале [-10,12] ;при изменении переменной x шагом 2 ;F(x) = a(x^2 + y^2 ) - b/(x^2 - y^2 ), ;где a = -2.5; b = 0.563; y=4 .model tiny, C .286 .code .startup
lea di, fx mov bx, -10 calc_loop: cmp bx, 12 jg finish call f, bx fstp dword ptr [di] add di, 4 add bx, 2 jmp calc_loop
finish: mov ax, 4c00h int 21h
;функция принимает целый параметр Х в стеке ;возвращает в st результат ;в случае деления на 0 возвращает 0 и FC=1 ;иначе FC=0 f proc x:word fild x ;x fmul st, st(0) ;x^2 fld y ;y,x^2 fmul st, st(0) ;y^2,x^2 fld st ;y^2, y^2,x^2 fadd st(0),st(2) ;y^2+x^2,y^2,x^2 fmul a ;a(y^2+x^2),y^2,x^2 fxch st(2) ;x^2,y^2,a(y^2+x^2) fsubrp ;x^2-y^2,a(y^2+x^2)
fldz ;загрузим 0 fcomp st(1) ;сравним с 0 (с удалением 0) fstsw ax ;флаги в ax sahf ;флаги в регистров флагов jz ZeroDevide ;=0 -> делить не будем! fdivr b ;b/(x^2-y^2),a(y^2+x^2) fsubr ;a(y^2+x^2)-b/(x^2-y^2) clc ret ZeroDevide: fstp st(1) ;уберем из стека st(1) и вернем 0 stc ret f endp
.data a dd -2.5 b dd 0.563 y dd 4.
.data? fx dd 12 dup (?)
end
В случае деления на 0 возвращает 0 и FC=1. При желании можно проанализировать. ----- Удачи! Ответ отправил: Лысков Игорь Витальевич, Модератор Ответ отправлен: 07.06.2010, 00:03 Номер ответа: 261941 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Оценка ответа: 5 Комментарий к оценке: Спасибо, огромное Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261941 на номер 1151 (Россия) | Еще номера » | Оценить выпуск » Нам очень важно Ваше мнение об этом выпуске рассылки! Скажите "спасибо" эксперту, который помог Вам! Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА на короткий номер 1151 (Россия) Номер ответа и конкретный текст СМС указан внизу каждого ответа. Полный список номеров » * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов) ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются. *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании. |
Комментариев нет:
Отправить комментарий