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

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


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

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

Коцюрбенко Алексей aka Жерар
Статус: Мастер-Эксперт
Рейтинг: 356
∙ повысить рейтинг »
Асмик Гаряка
Статус: Советник
Рейтинг: 118
∙ повысить рейтинг »
Куликов Роман Евгеньевич
Статус: 1-й класс
Рейтинг: 0
∙ повысить рейтинг »

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

Номер выпуска:1597
Дата выхода:17.04.2016, 14:21
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:18 / 8
Вопросов / ответов:1 / 1

Консультация # 189163: Здравствуйте! У меня возникли сложности с таким вопросом: У меня появились трудности, кто нибудь может мне помочь? Рассчитать и вывести значения выражений, при заданных пользователем значений х и а...

Консультация # 189163:

Здравствуйте! У меня возникли сложности с таким вопросом:

У меня появились трудности, кто нибудь может мне помочь?
Рассчитать и вывести значения выражений, при заданных пользователем значений х и а

Дата отправки: 11.04.2016, 20:17
Вопрос задал: MITAPRONVIK (Посетитель)
Всего ответов: 1
Страница онлайн-консультации »


Консультирует Лысков Игорь Витальевич (Старший модератор):

Здравствуйте, MITAPRONVIK!
Держите программу. Все вычисления производятся в сопроцессоре
Есть где поломать голову :)
Вещественные числа - вещь занимательная

Код (Assembler) :: выделить код
   .model   small
   .data 
sEnterA   db   "Enter a = $"   ;приглашение ввести а 
sEnterX   db   "Enter x = $"   ;приглашение ввести х 
sY   db   "y = $"      ;вывод y 
c10   dw   10      ; 10 основание системы счисления 
            ;числа-константы из формулы 
cm15   dw   -15 
c6   dw   6 
c34   dw   34 
c2   dw   2 
c16   dw   16 
c8   dw   8 
c14   dw   14 

            ;буфер для ввода строки-вещественного числа 
max   db   64      ;размер буфера 
len   db   ?      ;реальная длина 
String   db   64 dup (?)   ;сама строка 
 
sTemp   db   64 dup(?)   ;временный буфер для формирования строки-числа 
dig   dw   ?      ;цифра при обмене с сопроцессором 
 
a   dd   ?      ;числа, которые вводятся 
x   dd   ?
 
   .code         ;сегмент кода 
   .386         ;необходимо для команды fsin 
   .startup      ;инициализация сегментов для выбранной модели памяти 
 
   lea   dx, sEnterX
   call   InputFloat   ;вводим x 
   fstp   x      ;сохраним из стека сопроцессора в переменной x 
 
   lea   dx, sEnterA
   call   InputFloat   ;вводим a 
   fstp   a
 
   lea   dx, sY      ;выведем строку "y = " 
   mov   ah, 9 
   int   21h
 
   call   CalcY      ;считаем y по формуле, результат в стеке сопроцессора 
 
   call   float2str   ;преобразуем вещ число в стеке сопроцессора в строку 
 
   lea   dx, String   ;и выведем 
   mov   ah, 9 
   int   21h
 
   mov   ah, 0      ;ждем нажатие на клавишу 
   int   16h
   .exit   0 
 
CalcY   proc         ;расчет по формуле 
   fild   Cm15      ;-15 
   fidiv   C6      ;-15/6 
 
   fild  C34
   fld   x      ;x 
   fimul   C2      ;a*2 
   fsubp	   ;34-2x
   fimul  C2	   ;(34-2x)*2
   faddp	   ;-15/6 + (34-2x)*2
 
   fld   a      ;a 
   fsin         ;sin(a)
   fidiv   C8    ;sin(a)/8
   fiadd   C16   ;16+(sin(a)/8) 

   fdivp        ;(-15/6 + (34-2x)*2)/(16+(sin(a)/8))

   fisub    C14  ;(-15/6 + (34-2x)*2)/(16+(sin(a)/8)) - 14
   ret 
CalcY   endp 
 
InputFloat   proc      ;ввод вещественного числа 
   push   dx      ;сохраним адрес приглашения для повторного ввода 
   mov   ah, 9      ;выведем строку приглашения 
   int   21h
   
   lea   dx, max      ;вводим строку 
   mov   ah, 0ah
   int   21h
 
   lea   si, String   ;адрес строки 
   call   str2float   ;преобразовываем во float с проверкой синтаксиса 
   pushf         ;флаг С говорит о корректности строки, сохраним флажки 
   mov   ah, 2 
   mov   dl, 0dh      ;перевод на новую строку 
   int   21h
   mov   dl, 0ah
   int   21h
   popf         ;восстановим флажки 
   pop   dx      ;восстановим (уберем из стека) адрес приглашения 
   jc   InputFloat   ;ошибка - на повтор ввода! 
   ret         ;введенное число в стеке сопроцессора 
InputFloat   endp 
   
;Преобразование строки в вещественное число в st сопроцессора 
str2float   proc      ;преобразование строки в вещественное число 
   fldz         ;подготовим st=0 
   xor   dx, dx      ;число знаков после точки = 0 
   xor   bx, bx      ;bl = 0/1 знак числа +/-, bh = 1/0 знак уже введен/не задан 
   xor   di, di      ;число введенных цифр, для контроля позиции знака 
s2fNext:
   lodsb         ;очередной символ 
   cmp   al, 0dh      ;дошли до конца? 
   je   s2fSign      ;учтем знак 
   cmp   al, '+'      ;плюс? 
   jne   s2f_minus
   cmp   bh, 0      ;знак уже был введен? 
   jne   s2f_err      ;можно только раз 
   test   di, di 
   jne   s2f_err      ;знак можно писать только в первой позиции 
   mov   bh, 1      ;знак задан 
   jmp   s2fNext
s2f_minus:
   cmp   al, '-'      ;минус? 
   jne   s2f_point
   cmp   bh, 0      ;знак уже был введен? 
   jne   s2f_err      ;можно только раз 
   test   di, di 
   jne   s2f_err      ;знак можно писать только в первой позиции 
   mov   bx, 0101h   ;задаем знак - минус 
   jmp   s2fNext
s2f_point:
   cmp   al, '.'      ;точка 
   jne   s2f_digit
   test   dx, dx      ;точку можно задать только один раз 
   jne   s2f_err
   jmp   s2fInc
s2f_digit:         ;проверка на цифры 
   cmp   al, '0' 
   jb   s2f_err
   cmp   al, '9' 
   ja   s2f_err   
   inc   di      ;есть цифра 
   and   ax, 0fh      ;готовим разряд  
   mov   dig, ax      ; для загрузки в сопроцессор 
   test   dx, dx      ;если целая часть, то 
   je   s2fMul10   ; на умножение на 10 
   mov   cx, dx      ;иначе делим dx раз на 10 
   fild   dig      ; очередной разряд 
s2fdiv:
   fidiv   c10      ;делим dх раз 
   loop   s2fdiv
   faddp         ;складываем разряд за точкой с формируемым числом 
s2fInc:
   inc   dx      ;для точки только увеличиваем dх 
   jmp   s2fNext      ;пока не дойдем до конца 
 
s2fMul10:         ;целое число 
   fimul   c10      ;умножаем старое на 10 
   fiadd   dig      ;и прибавляем очередной разряд 
   jmp   s2fNext
s2fSign:         ;ввод числа закончен, учтем знак 
   cmp   bl, 0      ;если - 
   je   s2fRet
   fchs         ;то меняем знак 
s2fRet:
   clc         ;все ок 
   ret 
s2f_err:
   stc         ;ошибочка 
   fstp   st      ;выкидаем из стека число 
   ret 
str2float   endp 
 
;преобразование вещественного числа из st в строку по адресу String 
float2str   proc 
   push   es 
   push   ds 
   pop   es      ;es=ds 
 
   lea   di, sTemp   ;здесь будем формировать строку 
   ftst         ;Проверяем число 
   fstsw   ax      ;флаги в ax 
   sahf         ;флаги в регистре флагов 
   jnz   f2s_notZero   ;не 0 
   mov   dx, 1      ;длина 1 
   mov   bl, 0      ;сбрасываем знак 
   mov   ax, '0'      ;если 0, то выводим 0 
   stosw 
   jmp   f2s_Ret      ;на выход 
 
f2s_notZero:         ;не 0 
   mov   al, ' '      ; пока считаем, что положительное 
   jnc   f2s_sign   ;если оно отрицательное, 
   mov   al, '-'      ; то минус 
   fchs         ; и оставляем модуль числа. 
f2s_sign:
   stosb         ;знак числа 
; Пояснение далее пойдёт на примере.   ; ST(0) ST(1) ST(2) ST(3) ... 
; Отделим целую часть от дробной.   ; 73.25 ... что-то не наше 
   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], '$'   ;закроем строку знаком '$' для функции 9 
; и скопировать в буфер String не более 14 знаков 
   lea   si, sTemp
   lea   di, String 
   mov   dx, 0      ;длина 
f2s_6:
   lodsb 
   stosb            ;копируем 1 байт 
   inc   dx         ;считаем 
   cmp   dx, 14         ;копируем только 14 байт !!! (если получится число 
               ; с большим чем 14 байт знаков, то последние усекутся) 
   je   f2s_7         ;насильно закрываем '$'! 
   cmp   al, '$' 
   jne   f2s_6         ;копирование завершаем по '$' 
   dec   dx         ;отнимем 1 (посчитался байт '$') 
f2s_7:
   mov   byte ptr [di], '$'   ;закроем '$' (для случая обрезания) 
f2s_Ret:
   pop   es 
   ret 
float2str   endp 
   end

Консультировал: Лысков Игорь Витальевич (Старший модератор)
Дата отправки: 12.04.2016, 16:35

5
нет комментария
-----
Дата оценки: 12.04.2016, 17:05

Рейтинг ответа:

НЕ одобряю +2 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка  |  восстановить логин/пароль

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!


В избранное