Для разработки алгоритма перевода введенной строки в число проанализируем структуру числа в позиционной системе счисления (в такой системе счисления вес цифры определяется ее местоположением в числе):
2398=2*1000+3*100+9*10+8=2*103+3*102+9*101+8*100
Таким образом, для перевода строки в число из введенной строки «2398» необходимо последовательно выделять цифры и производить суммирование произведений этих цифр и множителей соответствующих позиции цифры в числе. Если буфер для ввода строки был организован, например, следующим образом:
BUF 05,00,05 DUP (?)
то после ввода строки «2398» он будет выглядеть (в шестнадцатеричной системе счисления) так:
05,04,32,33,39,38,0d
где первый байт – размер буфера, второй – количество введенных симво-лов (без завершающего символа CR), третий, четвертый, пятый, шестой и седьмой – коды символов «2», «3», «9», «8» и «CR» соответственно. Легко заметить, что для того, чтобы из кода цифры получить саму цифру необхо-димо из соответствующего кода вычесть 30h (шестнадцатеричный код нуля). Затем, последовательно в цикле (второй байт – количество введенных символов) выбирая цифры, формировать соответствующий множитель, вычислять произведение и производить суммирование. Нижеследующий фрагмент программы иллюстрирует описанный алгоритм (символы рассматриваются справа налево).
;Ввод числа в виде строки
MOV AH,0AH ;в AH номер функции
LEADX,BUF ;DS:DX адрес буфера для ввода
INT 21H
;Перевод строки в число, результат в DI
MOV DI,0
LEABX,BUF+1;в BX адрес второго элемента буфера
MOV CX,[BX] ;в CX количество введенных символов
XORCH,CH
MOV SI,1 ;в SI множитель
MET: PUSH SI ;сохраняем SI (множитель) в стеке
MOV SI,CX ;в SI помещаем номер текущего символа
MOV AX,[BX+SI];в AX помещаем текущий символ
XORAH,AH
POP SI ;извлекаем множитель (SI)из стека
SUB AX,30H ;получаем из символа (AX) цифру
MUL SI ;умножаем цифру (AX)на множитель (SI)
ADDDI,AX ;складываем с результирующим числом
MOV AX,SI ;помещаем множитель (SI) в AX
MOV DX,10
MUL DX ;увеличиваем множитель (AX) в 10 раз
MOV SI,AX ;перемещаем множитель (AX) назад в SI
LOOP MET ;переходим к предыдущему символу
Перевод чисел в различные системы счисления
В большинстве случаев перевод из одной системы счисления в дру-гую осуществляется последовательным делением, в нашем случае, при переводе из десятичной системы счисления в двоичную, восьмеричную и шестнадцатеричную алгоритм можно значительно упростить, заменив деление сдвигом.
Перевод из десятичной системы счисления в двоичную осуществляется последовательными сдвигами на один бит вправо. Таким образом, значение очередного бита можно вычислить, проанализировав флаг переноса CF (если CF=1 то анализируемый бит был равен 1, и если CF=0, то анали-зируемый бит – 0).
Перевод из десятичной системы счисления в восьмеричную осуществляется последовательными сдвигами на три бита вправо. После очередного сдвига все биты кроме трех младших обнуляются (например, наложением маски командой AND). Таким образом, в регистре получается восьмеричная цифра, для получения ее символьного отображения к значению в регистре необходимо прибавить код нуля (30h).
Перевод из десятичной системы счисления в шестнадцатеричную осуществляется последовательными сдвигами на четыре бита вправо. После обнуления всех битов кроме четырех младших в регистре получается десятичный эквивалент шестнадцатеричной цифры (число от 0 до 15). Для его представления в шестнадцатеричной символьной форме необходимо организовать таблицу соответствия, которая в простейшем случае пред-ставляет собой следующую строку «0123456789ABCDEF». При перекодировании значение десятичного эквивалента используется как смещение в таблице относительно ее начала (перекодировка может осуществляться при помощи команды XLAT).
Разбор программы
Задание: разработать программу перевода чисел из десятичной системы счисления в двоичную, восьмеричную и шестнадцатеричную. Числа должны вводиться в десятичной системе счисления, а выводятся – в двоичной, восьмеричной и шестнадцатеричной.
Прога получилась большая! кроме всего прочего в ней показано как работать с файлами в DOS, а также показано как описывать процедуры, сама по себе программа очень простая, всё понятно из коментариев. Работу с файлами мы рассмотрим далее, а здесь она только для примера.
Файл perevod.asm
.model tiny
.code
org 100h
start:
;выводим приглашение
mov dx,offset message3
mov ah,09h
int 21h
;вводим имя файла
mov ah,0Ah
mov dx,offset filename
int 21h
;получаем имя в буфере
mov si,2
mov di,0
mov cl,byte ptr [filename+1]
mov ch,0
lo:mov ah,filename[si]
mov buf[di],ah
inc di
inc si
loop lo
;перевод строки
mov dx,offset crlf
mov ah,09h
int 21h
call openfile;открываем файл
mov handle,ax
;выводим приглашение
mov dx,offset message1
mov ah,09h
int 21h
;вводим строку
mov ah,0Ah
mov dx,offset buffer
int 21h
;перевод строки
mov dx,offset crlf
mov ah,09h
int 21h
;перевод строки в число в регистре AX
xor di,di
xor ax,ax;ax текущее значение результата
mov cl,blen
xor ch,ch
xor bx,bx
mov si,cx;тут длина буфера
mov cl,10;тут множитель 10,для команды MUL
asc2bin:
mov bl,byte ptr bcontents[di]
sub bl,'0';вычитаем из цифры код нуля
jb ascer;если код цифры меньше чем код '0'
cmp bl,9;или больше чем код '9'
ja ascer
mul cx
add ax,bx
inc di
cmp di,si;продолжать пока счетчик+1 меньше числа символов
jb asc2bin
;теперь число расположено в регистре ax
inc ax;действие над числом (ну произвольное, для примера :))
;начинаем вывод числа в hex формате
push ax
mov ah,9
mov dx,offset message2
int 21h
pop ax
push ax
mov si,0;это позиция в буфере который будем писать в файл
mov buf2out[si],'H'
inc si
mov buf2out[si],'E'
inc si
mov buf2out[si],'X'
inc si
mov buf2out[si],' '
inc si
mov bx,ax;теперь в bx число для вывода в dec формате
xchg ah,al;поместить в al старший байт
call print_al_hex
pop ax;восстановить в al младший байт
call print_al_hex
;начинаем вывод числа в dec формате
mov dx,offset crlf
mov ah,09h
int 21h
mov ah,9
mov dx,offset message4
int 21h
mov ax,bx
call print_al_dec
;пишем в файл
mov ah,40h
mov bx,handle
mov cx,si
lea dx,buf2out
int 21h
mov ah,3eh
mov bx,handle
int 21h
;конец программы
ret
ascer:
mov dx,offset errms
mov ah,9
int 21h
ret
;процедура вывода числа в al в hex формате
print_al_hex:
mov dh,al
and dh,0Fh;младшие 4 бита в dh
shr al,4 ;старшие 4 бита в al
call print
mov al,dh;теперь здесь младшие 4 бита
print:
cmp al,10;эти три команды переведут цифру в al в код ASCII, так круче чем XLAT!
sbb al,69h
das
mov dl,al
mov buf2out[si],dl
inc si
mov ah,2
int 21h
ret;этот ret работает два раза
;процедура вывода числа в ax в dec формате
print_al_dec:
mov buf2out[si],0Dh
inc si
mov buf2out[si],0Ah
inc si
mov buf2out[si],'D'
inc si
mov buf2out[si],'E'
inc si
mov buf2out[si],'C'
inc si
mov buf2out[si],' '
inc si
mov cx,10
xor bx,bx
m1:cmp ax,10
jb m2
xor dx,dx
div cx
or dl,30h
push dx
inc bx
jmp m1
m2:or al,30h
push ax
inc bx
mov cx,bx
lop:pop dx
mov buf2out[si],dl
inc si
mov ah,2
int 21h
loop lop
ret
;процедура открытия файла - описатель в ax
openfile proc
mov ah,3ch
mov cx,0
mov dx,offset buf
int 21h
jnc nerr
mov dx,offset myerr
mov ah,9
int 21h
;перевод строки
mov dx,offset crlf
mov ah,09h
int 21h
nerr: ret
endp
;!!!!!!!!!!!!!!!!!!!!!!!!!ОПИСАНИЕ ДАННЫХ ПРОГРАММЫ!!!!!!!!!!!!!!!!!!!!!!!!!!!
handle dw ?;это описатель файла!
buf db 8 dup (0),0
;это буфер который мы запишем в файл!
buf2out db 20 dup (?),'$'
message1 db "Decimal number: $"
message2 db "Heximal number: $"
message4 db "New dec number: $"
message3 db "Enter file name: $"
filename db 9,?,9 dup (0),0
errms db "Error number:programm terminate!!!!!!!!!!!!!$"
myerr db "WARNING!!! File not create$"
crlf db 0Dh,0Ah,'$'
buffer db 6;максимальный размер для ввода числа
blen db ?;размер после ввода
bcontents: ;содержимое буфера числа за концом программы COM
end start
Компиляция:
c:\specprog\tasm\bin\tasm.exe perevod.asm
c:\specprog\tasm\bin\tlink.exe perevod.obj /t/x
Вот что получилось в результате: