Вопрос № 183219: Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: Помогите решить 2 задачи на ассемблере, ввиде 1 программы для "14" варианта(номера): Вот условие:
Вопрос № 183219:
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: Помогите решить 2 задачи на ассемблере, ввиде 1 программы для "14" варианта(номера):
Вот условие:
Требуется: 1)каждую функцию реализовать в ввиде отдельной подпрограммы 2)Использовать наиболее подходящий способ передачи аргумента 3)Сформировать макрокоманды, если вычисления встречаются более
1 раза. 4)Организовать ввод данных с клавиатуры и вывод результата на экран.
Расставте комментарии к коду, чтобы было легче ориентироваться и прежде всего понять код.
Отвечает Лысков Игорь Витальевич (Старший модератор) :
Здравствуйте, Юдин Евгений Сергеевич! Больше всего проблем не с самим вычислением, а с вводом/выводом Я адаптировал функции из пакета 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 (Россия) |
Еще номера »
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.