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

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


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

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

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

Boriss
Статус: Академик
Рейтинг: 2649
∙ повысить рейтинг »
Абаянцев Юрий Леонидович aka Ayl
Статус: Профессионал
Рейтинг: 2270
∙ повысить рейтинг »
Жерар
Статус: Профессор
Рейтинг: 2151
∙ повысить рейтинг »

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

Номер выпуска: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 (Россия) | Еще номера »
  • Отправить WebMoney:


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

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

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

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

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

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

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



    В избранное