Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 14.04.2015, 12:43   #1
R71MT
Участник клуба
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,428
По умолчанию Оптимизация процедур

Начал изучать ассемблер.., и часто возникают вопросы, на которые надеюсь получить от Вас ответы. Плаваю (в основном) в арифметике. Например, как в досе перемножить 2 десятичных числа и вывести результат на экран.
Регистры: 16-битные, числа вводятся с клавиатуры: 1234 * 12
Скачал много книг по-ассемблеру, но везде приводятся примеры с 1-байтовыми числами (2+2), а как быть, если число больше 10d ?? Здесь уже путаюсь..

При вводе..:
Цитата:
1. В ES:DI получаю ASCII-строку вида: 31 32 33 34 31 32 (ax=0, int16)
2. Дальше, в цикле перевожу её в числа: 01 02 03 04 01 02 (and al,0F)
3. Отсекаю нули у слов, и получаю: 12 34 12 (div ax,10; add al,dl)
4. Копирую первое слово в AX (AX=1234), оставшийся байт в BX (BX=0012)
5. Умножаю AX на BX (mul BX), и получаю AX=47A8, DX=0001 (0147A8h)
6. Корректирую результат через AAM: AX=1008, DX=0001
Правильно-ли я действую, или есть другие варианты?
Результат в DEC должен быть: 1234 * 12 = 14808d
Как перевести [AX=1008, DX=0001] в ASCII-строку 31 34 38 30 38, чтоб вывести результат на экран?
Нашедшего выход - затаптывают первым..
R71MT вне форума Ответить с цитированием
Старый 14.04.2015, 13:14   #2
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,238
По умолчанию

Цитата:
Копирую первое слово в AX (AX=1234), оставшийся байт в BX (BX=0012)
это вы в отладчике видите? В шестнадцатеричном виде?
тогда это не 1234d и не 12d, а 1234h (4660d) и 12h(18d), если перемножить числа 4660*18 = 83880d (а это и есть 0147A8h)

Вам нужно:
Ввести строку.
строку перевести в число.
Выполнить нужные вычисления.
Перевести результат в строку.
Вывести полученную строку.

посмотрите в FAQ по ассемблеру, там есть процедуры перевода
Serge_Bliznykov вне форума Ответить с цитированием
Старый 14.04.2015, 13:36   #3
R71MT
Участник клуба
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,428
По умолчанию

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
Вам нужно:
Выполнить нужные вычисления.
..выходит, что нужно перевести число в DEC перед вычислением, или переводить в DEC уже результат вычисления HEX?
Нашедшего выход - затаптывают первым..
R71MT вне форума Ответить с цитированием
Старый 14.04.2015, 13:51   #4
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,238
По умолчанию

Цитата:
Сообщение от R71MT Посмотреть сообщение
нужно перевести число в DEC перед вычислением
да. потому что нужно понять - у компьютера внутри все числа в двоичном виде.
хоть Вы напишите mov ax, 1234h, хоть mov ax, 1234
он всё ВНУТРИ переведёт в бинарный вид
но Вам принципиально важно, как заданы числа - в двоичном виде, десятичном, восьмеричном, шестнадцатеричном или в любом другом.
Поэтому, Вам нужно разобрать (распарсить) входную строку и преобразовать числовые значения.

если дана строка в ДЕСЯТИЧНОМ виде, то, после ввода строки нужно эти символы перевести в числовое значение, рассматривая заданные символы как ДЕСЯТИЧНУЮ запись числа.
После преобразования с полученным значением уже можно манипулировать - помещать его в регистры, использовать в вычисления и т.д. и т.п.

кстати, при преобразовании строка -> число вполне может возникнуть ошибочная ситуация, когда представленная строка НЕ ЯВЛЯЕТСЯ корректной числовой записью. В этом случае Вам придётся принимать решение, как обрабатывать эту ситуацию и что в этом случае делать.



p.s. кстати, а в каком смысле Вы использовали термин "примеры с 1-байтовыми числами" ?!
если что, что все числа меньше 256 - это "однобайтовые числа"! А Вы для тренировки вполне можете умножать, например, 10*17 или 13*13 или 12*12 или 12 * 14 ... (результат тоже будет однобайтовым).

Последний раз редактировалось Serge_Bliznykov; 14.04.2015 в 13:56.
Serge_Bliznykov вне форума Ответить с цитированием
Старый 14.04.2015, 15:03   #5
R71MT
Участник клуба
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,428
По умолчанию

Serge_Bliznykov, я создаю массив так (ввод с клавы 1234):
Код:
   mov cx,4
inputs:   ;------------; функция ввода/сохранения данных--|
  wLoop:
   xor  ax,ax
   int  16h            ; читаем ASCII-символ с клавиатуры
   int  29h            ; печатаем его
   and  al,0Fh         ; переводим ASCII в число
   mov  [di],al        ; запишем это число в ES:DI
   inc  di             ; переместим указатель
  loop wLoop           ; мотаем цикл, пока CX > 0
ret
..получаю в DI такое число: 01 02 03 04
Теперь, хочу получить число: 1234
Код:
rezult:   ;------------; математическая функция-----------|
;---------; т.е. каждое слово делю на 10 -----------------|
;---------;-----------------------------------------------|
   xor  di,di          ; указатель на начало массива
   mov  bx,10          ; BX - делитель/множитель
   mov  cx,2           ; длинна массива в словах

  nLoop:
   mov  ax,word[es:di] ; AX=0102
   div  bx             ; АХ=0010, DX=0002 (остаток)
   add  al,dl          ; AX=0012
   mov  byte[di],al    ; DI=12 (перезапись первого байта)
   add  di,2           ; читаю следующее слово
  loop  nLoop          ; ES:DI = 1234 (во-втором слове xchg al,ah)

;-----для примера, полученное число умножу на 10
   xor  di,di          ; начало массива
   mov  ax,word[di]    ; AX=1234 (множимое)
   mul  bx             ; BX= 0010 (множитель)               
   aam                 ; десятичная коррекция..
Процесс последнего участка кода в отладчике:
Код:
C:\>debug
-a
0CBE:0100 mov ax,1234
0CBE:0103 mov bx,10
0CBE:0106 mul bx
0CBE:0108 aam
0CBE:010A
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0CBE  ES=0CBE  SS=0CBE  CS=0CBE  IP=0100   NV UP EI PL NZ NA PO NC
0CBE:0100 B83412        MOV     AX,1234
-t
AX=1234  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0CBE  ES=0CBE  SS=0CBE  CS=0CBE  IP=0103   NV UP EI PL NZ NA PO NC
0CBE:0103 BB1000        MOV     BX,0010
-t
AX=1234  BX=0010  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0CBE  ES=0CBE  SS=0CBE  CS=0CBE  IP=0106   NV UP EI PL NZ NA PO NC
0CBE:0106 F7E3          MUL     BX
-t
AX=2340  BX=0010  CX=0000  DX=0001  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0CBE  ES=0CBE  SS=0CBE  CS=0CBE  IP=0108   OV UP EI PL NZ NA PO CY
0CBE:0108 D40A          AAM
-t
AX=0604  BX=0010  CX=0000  DX=0001  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0CBE  ES=0CBE  SS=0CBE  CS=0CBE  IP=010A   NV UP EI PL NZ NA PO NC
До коррекции, получил: AX=2340 DX=0001
После коррекции: AX=0604 DX=0001
Зачем нужна эта коррекция, если результат должен быть: 12340
Нашедшего выход - затаптывают первым..

Последний раз редактировалось R71MT; 14.04.2015 в 15:11.
R71MT вне форума Ответить с цитированием
Старый 14.04.2015, 15:24   #6
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,238
По умолчанию

да вы не ту сторону идёте...

посмотрите примеры ввода-вывода на винграде


ну или (с) Goodwin98

Ввод целого положительного или отрицательного числа числа.
Введенное число будет находиться в ax
Изменяя число - основание сс, можно вводить числа в различных системах до десятеричной.

Код:
InputInt proc 
 
    mov ah,0ah
    xor di,di
    mov dx,offset buff ; аддрес буфера
    int 21h ; принимаем строку
    mov dl,0ah
    mov ah,02
    int 21h ; выводим перевода строки
    
; обрабатываем содержимое буфера
    mov si,offset buff+2 ; берем аддрес начала строки
    cmp byte ptr [si],"-" ; если первый символ минус
    jnz ii1
    mov di,1  ; устанавливаем флаг
    inc si    ; и пропускаем его
ii1:
    xor ax,ax
    mov bx,10  ; основание сc
ii2:
    mov cl,[si] ; берем символ из буфера
    cmp cl,0dh  ; проверяем не последний ли он
    jz endin
    
; если символ не последний, то проверяем его на правильность
    cmp cl,'0'  ; если введен неверный символ <0
    jl er
    cmp cl,'9'  ; если введен неверный символ >9
    ja er
 
    sub cl,'0' ; делаем из символа число 
    mul bx     ; умножаем на 10
    add ax,cx  ; прибавляем к остальным
    inc si     ; указатель на следующий символ
    jmp ii2     ; повторяем
 
er:   ; если была ошибка, то выводим сообщение об этом и выходим
    mov dx, offset error
    mov ah,09
    int 21h
    int 20h
 
; все символы из буфера обработаны число находится в ax
endin:
    cmp di,1 ; если установлен флаг, то
    jnz ii3
    neg ax   ; делаем число отрицательным
ii3:
    ret
 
error db "incorrect number$"
buff    db 6,7 Dup(?)
InputInt endp
Serge_Bliznykov вне форума Ответить с цитированием
Старый 14.04.2015, 15:30   #7
R71MT
Участник клуба
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,428
По умолчанию

Serge_Bliznykov, вот это мне и надо было. Спасибо!!!
Нашедшего выход - затаптывают первым..
R71MT вне форума Ответить с цитированием
Старый 14.04.2015, 19:30   #8
R71MT
Участник клуба
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,428
По умолчанию

..всё ОК, но непонял некоторые нюансы.
Судя по-буферу и основанию СС, ваш код должен в AX считает сумму 4-х десятичных чисел с клавы. Опять-же однобайтных...

Ввожу с клавиатуры: 1234 = 1+2+3+4=10d
Код:
buff  db 6,7 Dup(0)   ; буфер после ввода: 6,4,31,32,33,34,0d,0

;--- первый цикл -----;
ii1:
    xor ax,ax         ; AX=0000
    mov bx,10         ; десятичное основание
ii2:
    mov cl,[si]       ; берём первый символ из буфера (31h)
    sub cl,'0'        ; отнимаем от него 30h (получили 01) 
    mul bx            ; умножаем на 10 (получили 10h)
    add ax,cx         ; прибавляем к остальным (???)
    inc si            ; указатель на следующий символ
    jmp ii2           ; повторяем
                      ; AX=0010
;--- второй цикл -----;
ii2:
    mov cl,[si]       ; берём второй символ из буфера (32h)
    sub cl,'0'        ; отнимаем от него 30h (получили 02h) 
    mul bx            ; умножаем на 10 (получили 20h)
    add ax,cx         ; прибавляем к AX
                      ; AX=0030h
;--- третий цикл -----;
                      ; AX=0060h
;--- четвёртый цикл --;
                      ; AX=00A0h
..на выходе, у нас АХ=00A0h, ..пахнет десятичной 10, но и только. Видимо, чтоб вывести его на экран в виде ASCII-символов 10, нужна ещё операция.

В общем - мне нужно чуть другое: умножить 1234 на 12 (введённые с клавиатуры), не используя регистр EAX, и вывести результат на экран, в виде десятичного числа, т.е. результат на экране должен быть 14808.
Нашедшего выход - затаптывают первым..
R71MT вне форума Ответить с цитированием
Старый 15.04.2015, 11:15   #9
R71MT
Участник клуба
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,428
По умолчанию

Вроде разобрался...
Ниже - универсальная процедурка "Convert", которая выводит результат в системах счисления(2/8/10), указаной в регистре ВХ. Правда имеется ограничение размера регистра AX, поэтому результат вычисления не должен превышать FFFFh (65535).

Если нужна арифметика с более/большими числами, то можно использовать регистр(EAX), тогда потолок результата возрастает до 4294967295.

Пример окна:
Код:
 Multiply registers: EAX=12345678
                     EBX=12
 ------------------------------------
 Decimal...........: 148148136
 Octal.............: 1065107650
 Binary............: 1000110101001000111110101000
Если не брать в счёт процедуру считывания ASCII-строки с клавиатуры, перевода её в число, и копирования в EAX, то код будет выглядеть так:
Код:
use16
org 100h
jmp start

string  db 13,10,' Multiply registers: EAX=12345678'
        db 13,10,'                     EBX=12$'
rezult  db 13,10,' ------------------------------------'
        db 13,10,' Decimal...........: $'
octal   db 13,10,' Octal.............: $'
binar   db 13,10,' Binary............: $'

start:
   mov  dx,string
   call message        ; инфа с состоянием регистров------------------|

   mov  eax,12345678
   mov  ebx,12
   mul  ebx            ; перемножаем регистры
   push eax            ; сохраним результат, для вывода DEC/OCT/BIN
   push eax
   push eax

   mov  dx,rezult
   call message        ; строка юзеру---------------------------------|
   pop  eax            ; снимаем результат со стека
   mov  ebx,10         ; вывод в десятичном формате
   call convert

   mov  dx,octal
   call message        ; строка юзеру---------------------------------|
   pop  eax            ; снимаем результат со стека
   mov  ebx,8          ; вывод в восьмиричном формате
   call convert

   mov  dx,binar
   call message        ; строка юзеру---------------------------------|
   pop  eax            ; снимаем результат со стека
   mov  ebx,2          ; вывод в двоичном формате
   call convert

   xor  ax,ax          ; конец программы------------------------------|
   int  16h
   int  20h

;//--------------------; необходимые процедурки-----------------------|
convert:
   xor  ecx,ecx        ; сбросим счётчик EAX'совских цифр
fnDiv:
   xor  edx,edx        ; здесь будет остаток
   div  ebx            ; делим EAX на систему счисления
   push edx            ; сохраним остаток
   inc  ecx            ; считаем количество цифр
   or   eax,eax        ; повторяем пока не 0
   jnz  fnDiv
fnOut:
   pop  eax            ; снимаем изменённый EAX
   cmp  al,09          ; проверим на 9
   jle  noHex          ; если меньше/равно, не корректируем
   add  al,7           ; коррекция..
noHex:
   add  al,30h         ; переводим в ASCII
   int  29h            ; печатаем символ
   loop fnOut          ; читаем следующую цифру 
ret                    ; выходим из процедуры

message:               ; функция вывода сообщений
   mov  ah,9
   int  21h
ret
Нашедшего выход - затаптывают первым..
R71MT вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
организация процедур Jalgas-xan Паскаль, Turbo Pascal, PascalABC.NET 0 17.01.2013 15:32
оптимизация процедур поиска(delphi) jandr Помощь студентам 1 23.12.2012 00:00
Использование процедур WTF??? Паскаль, Turbo Pascal, PascalABC.NET 0 21.12.2011 14:24
Проследовательность процедур ramzes777 Помощь студентам 4 09.11.2011 18:43
Массив процедур garik Общие вопросы Delphi 0 18.03.2009 21:08