Хостинг портала RFpro.ru: Московский хостер Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64 РАССЫЛКИ ПОРТАЛА RFPRO.RU Лучшие эксперты данной рассылки Номер выпуска: | 1449 | Дата выхода: | 22.05.2011, 21:00 | Администратор рассылки: | Лысков Игорь Витальевич (Старший модератор) | Подписчиков / экспертов: | 215 / 64 | Вопросов / ответов: | 1 / 1 | Вопрос № 183219: Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: Помогите решить 2 задачи на ассемблере, ввиде 1 программы для "14" варианта(номера): Вот условие: Вопрос № 183219: Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: Помогите решить 2 задачи на ассемблере, ввиде 1 программы для "14" варианта(номера):
Вот условие:

Требуется: 1)каждую функцию реализовать в ввиде отдельной подпрограммы 2)Использовать наиболее подходящий способ передачи аргумента 3)Сформировать макрокоманды, если вычисления встречаются более 1 раза. 4)Организовать ввод данных с клавиатуры и вывод результата на экран.
Расставте комментарии к коду, чтобы было легче ориентироваться и прежде всего понять код.
Спасибо.
Отправлен: 17.05.2011, 20:35 Вопрос задал: Юдин Евгений Сергеевич (8-й класс) Всего ответов: 1 Страница вопроса » Отвечает Лысков Игорь Витальевич (Старший модератор) : Здравствуйте, Юдин Евгений Сергеевич! Больше всего проблем не с самим вычислением, а с вводом/выводом Я адаптировал функции из пакета MASM32.  Удачи Вам в разборе кода!
Код : .386 ;необходимо для команды fcos ;макро для вычисления y^x ;в st должно находиться xlog[2]y POWER MACRO fld st ;x*log[2]y->st(1) frndint ;округляем st до целого fsub st(1),st ;st(1)-=st fxch ;st(1)<->st f2xm1 ;st=(2 в степени st) - 1 fld1 ;1->st fadd ;st+=1 fscale ;y^x = st * (2 в степени st(1)) fstp st(1) ;чтобы убрать значение из st(1) ENDM ;ln(st) LN MACRO fld1 ;1 fxch ;st(1)<->st fyl2x ;st=1*log[2]st=log[2]x fldl2e ;st=log[2]e fdivp ;st=st(1)/st=log[2]x/log[2]e=lnx ENDM ;ln^3(1+cos|z-1|) CALC_ln3 MACRO fld z ;z->st fld1 ;1 fsubp ;st-1->st fabs ;abs(st) fcos ;st=cos(|st|) fld1 ;1 fadd ;st=st+1 LN ;ln(st) fld st ;st(1)=st fld st ;st(2)=st(1)=st fmulp ;st^2 fmulp ;находим ln(1+cos|z-1|)^3 ENDM cseg segment para use16 public 'code' assume cs:cseg, ss:dseg, ds:dseg, es:dseg start: mov ax, dseg mov ds, ax ;настроим сегментные регистры mov es, ax ;на сегмент dseg mov ss, ax mov sp, 0fffeh ;стек в вершине ;введем данные lea dx, sEnterX ;строка приглашения call GetFloat ;вводим вещественное, результат в st fstp x ;сохраним в x lea dx, sEnterY call GetFloat fstp y ;y lea dx, sEnterZ call GetFloat fstp z ;z call calc_a ;получаем в st расчет a fst a ;сохраним в a push offset sNum ;адрес буфера для числовой строки call FloatToStr ;преобразовываем lea si, sA ;строка пояснения 'a=' lea bx, sNum ;числовая строка call prStr ;выводим call calc_b ;получаем в st расчет b fst b push offset sNum call FloatToStr lea si, sB lea bx, sNum call prStr ;аналогично mov ax,4c00h int 21h ;выход в ДОС GetFloat proc ;ввод вещественного числа mov ah, 9 int 21h ;выводим приглашение из dx lea dx, sBuf mov ah, 0ah int 21h ;вводим строку lea ax, string ;адрес строки push ax ;параметр в стек call StrToFloat ;преобразовываем в вещественное ret GetFloat endp prsz proc ;вывод стоки ASCIIZ [si] lodsb cmp al, 0 je prret int 29h jmp prsz prret: ret prsz endp prStr proc near ;вывод двух строк ASCIIZ call prsz ;первая [si] mov si, bx call prsz ;вторая [bx] ret prStr endp ;расчет a ;результат в st calc_a proc CALC_ln3 ;ln^3(1+cos|z-1|) fld y ;st = y fmul c071 ;st = 0.71y faddp ;st = ln^3(1+cos|z-1|)+0.71y fld1 ;1 fld x ;x fld st ;x fld st ;x fmulp ;x*x fmulp ;x*x*x fdivp st(1), st ;x^-3 fmul c2 ;2x^-3 fld z ;z fmul y ;z*y fmul c0005 ;0.005zy faddp ;2x^-3 + 0.005zy fdiv ;(ln^3(1+cos|z-1|)+0.71y)/ ret ; (2x^-3 + 0.005zy) calc_a endp ;расчет b ;результат в st calc_b proc CALC_ln3 ;ln^3(1+cos|z-1|) fadd c5 ;ln^3(1+cos|z-1|) + 5 ret calc_b endp ;П/п конвертации float <-> ASCII ;Можно особо не вникать :). Переделан код из пакета MASM32 ; вспомогательная п/п конвертации float в ASCII. ; результат всегда - 18 байт с лидирующими нулями ; ; На входе: ST(0) = число для конветации, 0 <= ST(0) < 1E19. ; szTemp = 18-байтовый буфер. ; ; На выходе: szTemp = сконвертированный результат. FloatToBCD PROC push bp mov bp, sp sub sp, 10 ;выделим буфер в стеке push si di ; инструкция fbstp конвертирует число из st в упакованное BCD число ; из 10 байт, 2 цифры на байт ; знак в старшем полубайте мы игнорируем fbstp [bp-10] ;[bp-10] адрес временного буфера ; распаковываем BCD в ASCII. lea si, [bp-2] ;BCD, начинаем с правого края, знаковый игнорируем lea di, szTemp ;сюда распакуем mov cx, 9 ;9 байт convertBCDloop: mov al, [si] ; xxxx xxxx AAAA BBBB dec si ;сдвигаем влево rol ax, 12 ; BBBB xxxx xxxx AAAA rol ah, 4 ; xxxx BBBB xxxx AAAA and ax, 0f0fh ; 0000 BBBB 0000 AAAA add ax, 3030h ; 3B3A mov [di], ax ;пишем add di, 2 loop convertBCDloop pop di si mov sp, bp pop bp ret FloatToBCD ENDP sBuffer equ word ptr [bp+4] ;параметр - адрес буфера iExp equ word ptr [bp-2] ;експонента stat equ word ptr [bp-4] ;сохрпненные режимы сопроцессора mystat equ word ptr [bp-6] ;устанавливаемые режимы сопроцессора ;преобразовываем вещественное из st в строку, адрес которой в стеке FloatToStr PROC push bp mov bp, sp sub sp, 6 ;под 3 переменные push si di ;инициализация сопроцессора fclex fstcw stat mov mystat, 027fh fldcw mystat mov di, sBuffer ;буфер ;прверим на 0 ftst ;st = 0? fstsw ax ;флаги в ax sahf ;из ah в PSW jnz floatNotZero ;можно анализировать mov ax, '0' ;для 0, запишем '0',0 stosw jmp FTSRet floatNotZero: ;что-то есть jg floatPositive ;число положительное? fabs ;взять модуль числа mov byte ptr [di], '-' ; нарисуем знак миеус inc di ;продвигаем указатель floatPositive: ;положительное число fld st(0) ;st(1) = st(0) ;найдем ближайшую снизу степень 10 ;мы не можем добиться большой точности из-за округления ; ;log2(Y) x log10(2) = log10(fpin) fxtract ; ST => мантисса, експонента fstp st(0) ; мантиссу убираем fldlg2 ; push log10(2) fmulp st(1), st ; ST = log10(fpin), fpin fistp iExp ; ST = fpin ; 8-байтовые вещественные числа формата double могут обеспечить только ; 16 точных знаков после запятой (вообще говоря, 15.9) ; Поэтому для чисел только с точкой, без порядка, ограничим диапозон 1E17 cmp iExp, 16 ;проверяем порядок jae eForm ;на формирование числа с порядком ;проверим, целое ли число? fld st(0) ; ST(1) = ST frndint ; округляем fcomp st(1) ; сравниваем fstsw ax sahf jnz eForm ;не целое - формируем число с порядком ; Число целое - просто конвертируем call FloatToBCD ; Найдем начало числа в 18-байтном буфере mov si, 17 mov cx, iExp sub si, cx inc cx lea si, szTemp[si] ; Уберем возможный лидирующий 0 cmp byte ptr [si], '0' jne CopyNum inc si dec cx ; Копируем числовую строку в результирующую строку CopyNum: rep movsb jmp FTSRet ; Используем формат [-]d.ddddddE+ddd. ; Ограничимся 7 цифрами eForm: mov ax, 6 sub ax, iExp ;выравниваем експоненту call PowerOf10 ;умножаем на 10^ax ; Имеем или >= 7 цифр, или < ; Определимся fcom ten7 ;сравним с 1.0e6 fstsw ax sahf jnc convertBCD ;>= 7 - на конвертацию fmul ten ;нет - добавим еще один разряд dec iExp ; Конвертируем в BCD convertBCD: call FloatToBCD lea si, szTemp+11 ; адрес первых 7 байт мантиссы ; Если экспонента между -1 и 6, то можно обойтись без научной нотации mov cx, iExp cmp cx, -1 jl scientific cmp cx, 6 jg scientific ; Будем копировать cx+1 цифр, точку и оставшиеся 6-cx цифр ; Если экспонента 0, добавим лидирующий 0 cmp cx, -1 jne formNum mov byte ptr [di], '0' inc di formNum: inc cx rep movsb mov byte ptr [di], '.' inc di mov cx, 6 sub cx, iExp rep movsb ; уберем незначащие завершающие нули TrimOffZeros: cmp byte ptr [di-1], '0' jne CmpPoint dec di jmp TrimOffZeros ; Если убрали до точки, то уберем и ее тоже CmpPoint: cmp byte ptr [di-1], '.' jne ToExit dec di ; Готово! ToExit: jmp FTSRet ; копируем мантиссу, сначала одну цифру, потом точку, потом оставшиеся 6 цифр scientific: movsb ; первая цифра mov byte ptr [di], '.' ; точка inc di movsw ; 6 цифр после точки movsw movsw ; уберем незначащие завершающие нули TrimOffZeros2: cmp byte ptr [di][-1], '0' jne exponent dec di jmp TrimOffZeros2 ; формируем порядок exponent: mov byte ptr [di], 'e' ; экспонента mov ax, iExp test ax, ax ; знак jl negativeExp mov byte ptr [di][1], '+' jmp formExp negativeExp: mov byte ptr [di][1], '-' neg ax formExp: ; преобразуем в три цифры mov cx, 10 xor dx, dx div cx add dl, '0' mov [di][4], dl ; единицы xor dx, dx div cx add dl, '0' mov [di][3], dl ; десятки xor dx, dx div cx add dl, '0' mov [di][2], dl ; сотни add di, 5 ; продвинем указатель ; завершаем строку и выходим FTSRet: mov byte ptr [di], 0 fldcw stat ; восстанавливаем состояние fwait ; сопроцессора pop di si mov sp, bp pop bp ret 2 FloatToStr ENDP ; Умножение числа на 10^ax (для внутреннего употребления) ; ; На входе: AX = степень 10, -4932..4932. ; ST(0) = число ; На выходе: ST(0) = число x 10^ax PowerOf10 PROC push si di mov si, 10 ;длина одного элемента в таблице mov cx, ax ;сохраним знак числа mov bx, ax ;сохраним число test ax, ax ;проверим на знак jge PONext neg bx ;bx = |ax| PONext: fld1 ;1 ;идем по разрядам mov al, bl and ax, 0fh ;единицы jz tensDigit ;0 - ничего не делаем mul si ;*длину элемента тавлицы mov di, ax ;di - адрес множителя в таблице fld ten_1[di-10] ;-10 из-за того, что таблица начинается с 1 fmulp st(1), st ;умножаем tensDigit: mov al, bl shr al, 4 and ax, 0fh ;десятки (16-ричные) jz hundredDigit mul si mov di, ax fld ten_16[di-10] fmulp st(1), st hundredDigit: mov al, bh and ax, 1fh ;сотни (16-ричные) jz setSign mul si mov di, ax fld ten_256[di-10] fmulp st(1), st setSign: test cx, cx ;учтем знак порядка jl negativeSign fmulp st(1), st ;x^a jmp PORet negativeSign: fdivp st(1), st ;1/x^|ax| PORet: pop di si ret PowerOf10 ENDP ; ; Конвертация строки в вещественное число ; Вход: адврес строки - параметром в стеке ; Выход: число в ST szIn equ word ptr [bp+4] ;параметр - адрес строки sign equ byte ptr [bp-1] ;знак мантиссы expsign equ byte ptr [bp-2] ;знак порядка decimal equ word ptr [bp-4] ;позиция точки stat equ word ptr [bp-6] ;старое состояние сопроцессора temp equ word ptr [bp-8] ;переменная StrToFloat PROC push bp mov bp, sp sub sp, 8 ;выделим место в стеке под переменные push si di xor ax, ax ;пока считаем, что все положительное mov sign, al mov expsign, al mov decimal, -1 ;без точки fstcw stat ;настроим режим сопроцессора mov temp, 027fh fldcw temp ; Определимся со знаком mov si, szIn ;адрес строки mov al, [si] cmp al, '+' ;указан +? jne STFCmpMenus inc si ;сместим si mov al, [si] ;читаем следующий jmp STFCmpZero STFCmpMenus: cmp al, '-' ;-? jne STFCmpZero inc si ;сместим si mov sign, 1 ;пометим, что отрицательное mov al, [si] ;читаем следующий STFCmpZero: cmp al, 0 ;нулевая строка? je STFExit ; Инициализация сопроцессора fclex xor bx, bx ;число цифр до точки fldz xor cx, cx ;экспонента ;основной цикл анализа ; si = адрес строки ; al = очередной символ ; bx = число цифр до точки ; cx = экспонента ; ST(0) = аккумулятор cvtloop: cmp al, 'E' ;экспонента? je doExponent cmp al, 'e' je doExponent cmp al, '.' ;точка? jne cvtDigit mov decimal, bx ;запомним позицию точки jmp cvtNext ;и на продолжение cvtDigit: ;цифры sub al, '0' ;конвертируем ASCII в число jb STFFinish ;не цифра - прекращаем cmp al, 9 ja STFFinish ;не цифра - прекращаем mov temp, ax ;очередной разряд fmul ten ;d *= 10 fiadd temp ;d += очередной разряд inc bx ;инкремент числа цифр cvtNext: inc si ;на следующий символ mov al, [si] ;читаем его test al, al ;проверяем на 0 jnz cvtloop jmp STFFinish ;строка кончилась ; Получили мантиссу в ST ; Займемся порядком ; si = адрес строки ; al = очередной символ ; bx = счетчик цифр ; cx = экспонента ; ST(0) = мантисса doExponent: inc si mov al, [si] ;очередной символ test al, al ;конец? jz STFFinish ; Проверим порядок на знак cmp al, '+' jne expCmpMenus inc si mov al, [si] jmp expCmpZero expCmpMenus: cmp al, '-' jne expCmpZero inc si mov expsign, 1 ;порядок отрицательный mov al, [si] expCmpZero: test al, al ;конец? jz STFFinish expLoop: ;конвертируем порядок в число sub al, '0' jb STFFinish ;нецифра - завершаемся cmp al, 9 ja STFFinish xchg ax, cx mov dx, 10 imul dx add cx, ax ;накапливаем число в cx inc si mov al, [si] ;очередной символ test al, al ;конец? jnz expLoop ; Выравним мантиссу с учетом порядка ; ST(0) = мантисса ; cx = невыровненный порядок ; bx = общее число цифр STFFinish: cmp expsign, 0 je STFPoint neg cx ;отрицательный порядок STFPoint: mov ax, decimal ;позиция точки cmp ax, -1 je STFMult ;а не было точки sub bx, ax ;bx = число цифр справа от точки sub cx, bx ;выравниваем порядок ; Умножаем на 10^порядок ; ST(0) = мантисса ; cx = порядок STFMult: mov ax, cx call PowerOf10 ; Учтем знак числа cmp sign, 0 je STFExit fchs STFExit: fldcw stat mov ax, si ;вернем, на всякий случай, в ax ; адрес во входном буфере pop di si mov sp, bp pop bp ret 2 StrToFloat ENDP cseg ends dseg segment use16 para public 'data' ;переменные x dd ? y dd ? z dd ? ; a dd ? b dd ? ;константы для решения задачи c071 dd 0.71 c2 dd 2. c0005 dd 0.005 c5 dd 5. ;таблицы для быстрого умножения на 10^порядок ten_1 dt 1.0e1 ;для единиц dt 1.0e2 dt 1.0e3 dt 1.0e4 dt 1.0e5 dt 1.0e6 dt 1.0e7 dt 1.0e8 dt 1.0e9 dt 1.0e10 dt 1.0e11 dt 1.0e12 dt 1.0e13 dt 1.0e14 dt 1.0e15 ten_16 dt 1.0e16 ;для десятков dt 1.0e32 dt 1.0e48 dt 1.0e64 dt 1.0e80 dt 1.0e96 dt 1.0e112 dt 1.0e128 dt 1.0e144 dt 1.0e160 dt 1.0e176 dt 1.0e192 dt 1.0e208 dt 1.0e224 dt 1.0e240 ten_256 dt 1.0e256 ;для сотен dt 1.0e512 dt 1.0e768 dt 1.0e1024 dt 1.0e1280 dt 1.0e1536 dt 1.0e1792 dt 1.0e2048 dt 1.0e2304 dt 1.0e2560 dt 1.0e2816 dt 1.0e3072 dt 1.0e3328 dt 1.0e3584 dt 1.0e4096 dt 1.0e4352 dt 1.0e4608 dt 1.0e4864 ;константы, используемые при преобразованиях ten dq 10.0 ten7 dq 1.0e6 ten17 dq 1.0e17 ;буфер для внутреннего преобразования szTemp db 18 dup (0) ;буфер для получения ответа sNum db 20 dup (0) ;строки приглашения и результата sEnterX db 'Enter x: $' sEnterY db 0dh,0ah,'Enter y: $' sEnterZ db 0dh,0ah,'Enter z: $' sA db 0dh,0ah,'a = ',0 sB db 0dh,0ah,'b = ',0 ;структура для запроса строки по функции 0ah sBuf db 32 cnt db ? string db 32 dup (?) dseg ends end start ----- Люби своего ближнего, как самого себя Ответ отправил: Лысков Игорь Витальевич (Старший модератор) Ответ отправлен: 20.05.2011, 13:04 Номер ответа: 267266 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru
Оценка ответа: 5 Комментарий к оценке: Проделана гигантская работа - большое вам спасибо! Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 267266 на номер 1151 (Россия) | Еще номера » | Оценить выпуск » Нам очень важно Ваше мнение об этом выпуске рассылки! Скажите "спасибо" эксперту, который помог Вам! Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА на короткий номер 1151 (Россия) Номер ответа и конкретный текст СМС указан внизу каждого ответа. Полный список номеров » * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов) ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются. *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании. |
Комментариев нет:
Отправить комментарий