PDA

Просмотр полной версии : Перевод чисел в системы счисления



Pegasik
08.04.2008, 10:00
Здравствуйте. Нужно перевести 3 числа в 8-ю, 2-ю, 16-ю с.с.
Числа: 6219, 0.479, 986,207 (десятичные)
Сейчас работаю над числом 6219 (до дробных пока не добрался), перевёл его в 8-ю и 16-ю, а вот с 2-й возникла проблема, не правильно записывается в массив.
Исходник:
.MODEL tiny
.STACK 100h
.DATA
String db 5 dup (?),'$' ; Резервируем 5 байт для строки
StringEnd = $-1 ; Указывает на символ '$'
Number = 6219
Mes_1 db 0dh, 0ah, "Chislo 6219 v 16-y sisiteme schisleniya - ", "$"
Mes_2 db 0dh, 0ah, "Chislo 6219 v 8-y sisiteme schisleniya - ", "$"
Mes_3 db 0dh, 0ah, "Chislo 6219 v 2-y sisiteme schisleniya - ", "$"

Flag db 01h
.CODE
ORG 100h


Start:
push ax
push bx
push cx
push dx

mov ax,@data
mov ds,ax
mov es,ax

lea dx,Mes_1
mov ah,09h
int 21h

mov bl,Flag

;------------------Перевод числа в 16-ю с.с.-----------------------------

std ; Устанавливаем ОБРАТНЫЙ порядок записи
lea di,StringEnd-1 ; ES:DI = последний символ строки String
mov ax,Number ; Заносим в AX число для перевода
mov cx,16 ; Задаемся делителем CX = 16
_16_System:
xor dx,dx ; Обнуляем DX (для деления)
div cx ; Делим DX:AX на CX (16),
; Получаем в AX частное, в DX остаток
xchg ax,dx ; Меняем их местами (нас интересует остаток)
add al,'0' ; Получаем в AL символ цифры
cmp al,'9' ; Проверяем если цифра
jbe zapis ; Переходим на запись

add al,'A'-('9'+1) ; Если символ, корректируем
jmp zapis

zapis:
stosb ; И записываем ее в строку

cmp bl,04h
jge zap_2
jmp zap_16_8
zap_2:
inc di
; dec ch
cmp ch,0Fh
jne Met
jmp vivod

zap_16_8: xchg ax,dx ; Восстанавливаем AX (частное)
or ax,ax ; Сравниваем AX с 0
jne _16_System ; Если не ноль, то повторяем
jmp vivod

;------------------Перевод числа в 8-ю с.с.-----------------------------

_8_System:
lea dx,Mes_2
mov ah,09h
int 21h

std ; Устанавливаем ОБРАТНЫЙ порядок записи
lea di,StringEnd-1 ; ES:DI = последний символ строки String
mov ax,Number ; Заносим в AX число для перевода
mov cx,8 ; Задаемся делителем CX = 8
jmp _16_System

;-----------------Перевод числа в 2-ю с.с.-------------------------------

_2_System:
lea dx,Mes_3
mov ah,09h
int 21h
std ; Устанавливаем ОБРАТНЫЙ порядок записи
lea di,StringEnd-1 ; ES:DI = последний символ строки String
mov ax,Number ; Заносим в AX число для перевода
mov cl,16-1 ; 16-битный регистр, будем выводить по 4 бита (0..F)
xchg dx,ax ; Сохраняем число в DX

mov ch,0


Met:
mov ax,dx ; Восстанавливаем число в AX
shr ax,cl ; Сдвигаем на CL бит вправо
and al,1 ; Получаем в AL цифру 0..15
add al,'0' ; Получаем в AL символ цифры
sub cl,1 ; Уменьшаем CL на 1 для следующей цифры
inc ch
jnc zapis ; Если знаковый CL >= 0, то повторяем
; И записываем ее в строку
jmp zapis

;z1:
; inc di
; dec ch
; cmp ch,0
; jne z1
; jmp vivod

;-----------------Вывод строки на экран----------------------------------
vivod:
mov ah,09h
; lea dx,[di+1] ; Заносим в DX адрес начала строки
lea dx,String ; Заносим в DX адрес начала строки
int 21h ; Выводим ее на экран
add bl,01h
cmp bl,02h
je _8_System

add bl,01h
cmp bl,04h
je _2_System

mov ax,4c00h
int 21h ; Выходим из программы

push ax
push bx
push cx
push dx

END Start

Буду признателен за помощь.

Pegasik
08.04.2008, 10:02
Я так понимаю не правильно работает stosb, но не могу понять как его вылечить

Pegasik
08.04.2008, 10:03
Результат выполнения:
16-я - 184В
8-я - 14113
2-я - 14111

airyashov
08.04.2008, 10:46
да есть над чем подумать :)
что-то Я сомневаюсь в вашем авторстве.


.MODEL tiny !!!
.STACK 100h ???
.DATA ???
...
.CODE
ORG 100h


Start:
push ax ?
push bx ?
push cx ?
push dx ?

mov ax,@data ?
mov ds,ax ?
mov es,ax ?

...

lea di,StringEnd-1 ; ESI = последний символ строки String ???

...
sub cl,1 ; Уменьшаем CL на 1 для следующей цифры
inc ch
jnc zapis ; Если знаковый CL >= 0, то повторяем ???
; И записываем ее в строку
jmp zapis
...

mov ax,4c00h
int 21h ; Выходим из программы

push ax ?
push bx ?
push cx ?
push dx ?

END Start

Pegasik
08.04.2008, 10:55
простите, не совсем понял ваш ответ. Насчёт авторства, читал кучу статей по переводу чисел, вот что понял то и написал.

airyashov
08.04.2008, 11:04
Я так понимаю не правильно работает stosb, но не могу понять как его вылечить

если насчет двоичной, то основная ошибка здесь


sub cl,1 ; Уменьшаем CL на 1 для следующей цифры
inc ch
jnc zapis ; Если знаковый CL >= 0, то повторяем
; И записываем ее в строку
jmp zapis

и и 5 байт для двоичного представления не хватит

String db 5 dup (?),'$' ; Резервируем 5 байт для строки

airyashov
08.04.2008, 11:06
простите, не совсем понял ваш ответ. Насчёт авторства, читал кучу статей по переводу чисел, вот что понял то и написал.
Такое ощущение что из разных программ в одну все собрано и код логически трудно понять

Pegasik
08.04.2008, 11:17
А Вы не подскажете можно использовать в программе 2 раза stosb, я пробовал его вставить при переводе в двоичнуй, но выдаёт ошибку и пришлось прыгать по всей программе

airyashov
08.04.2008, 11:28
Можно сколько угодно раз, только за регистрами используемыми следите, но для начала лучше процедурно оформить программу, структурировать или отдельно для двоичной напишите.

Pegasik
08.04.2008, 11:38
Спасибо за ответы, буду исправлять.
Если не трудно, скажите, лучше использовать stosb или организовать через стэки?

airyashov
08.04.2008, 11:55
Это только вам решать, что использовать. Стек наверное проще будет в сохранении, но печатать оттуда не очень удобно.

Pegasik
09.04.2008, 11:37
Переделал прогу слегка. Разобрался с переводом в 2-ю систему счисления, всё работет отлично. Но теперь возникает другой вопрос с дробями. Я хочу число сразу распознать как целое или дробное. Для этого мне нужно пройтись по нему до запятой (если дробное) отделить целую часть от дробной. Целую часть можно сделать по уже написаной процедуре, а для дробной написать новую.
Подскажите пожалуйста, как разделить целую часть от дробной.

Pegasik
09.04.2008, 11:40
Вот что получилось:


.MODEL Small
.STACK 100h
.DATA
String db 16 dup (?),'$' ; Резервируем 16 байт для строки
StringEnd = $-1 ; Указывает на символ '$'
Number = 6219
Mes_1 db 0dh, 0ah, "Chislo 6219 v 16-y sisiteme schisleniya - ", "$"
Mes_2 db 0dh, 0ah, "Chislo 6219 v 8-y sisiteme schisleniya - ", " $"
Mes_3 db 0dh, 0ah, "Chislo 6219 v 2-y sisiteme schisleniya - ", " $"
.CODE
ORG 100h


Start:
mov ax,@data
mov ds,ax
mov es,ax

lea dx,Mes_1
mov ah,09h
int 21h
mov ax,Number
mov bx,16
std
lea di,StringEnd-10
call Perevod_num
mov ah,09h
lea dx,String
int 21h

lea dx,Mes_2
mov ah,09h
int 21h
mov ax,Number
mov bx,8
lea di,StringEnd-9
call Perevod_num
mov ah,09h
lea dx,String
int 21h

lea dx,Mes_3
mov ah,09h
int 21h
mov ax,Number
mov bx,2
lea di,StringEnd-1
call Perevod_num
mov ah,09h
lea dx,String
int 21h


mov ah,8
int 21h
ret

Break db 13,10
;---------------------------------Перевод числа-----------------------------
Perevod_num proc

push dx
push di
push cx

xor cx,cx

Proverka_num:

xor dx,dx
div bx
xchg ax,dx
add al,'0'
cmp al,'9'
jbe Cifra
add al,'A'-('9'+1)

Cifra:
stosb
xchg ax,dx
inc cx
test ax,ax
jne Proverka_num

pop cx
pop di
pop dx
ret

Perevod_num endp
end Start

somewhere
09.04.2008, 12:53
Подскажите пожалуйста, как разделить целую часть от дробной.
Использовать FPU - сначала загрузить число в стек, потом выгрузить только целую часть в переменную. Не забыть предварительно задать FPU правило округления через управляющее слово. Дробная часть есть модуль разности исходного числа и его целой части. Перевод дробной части основан на последовательном умножении на 2 и сноса первой цифры после умножения. Подробнее в разделе "Алгоритмы" - там есть пример на Паскале.

Pegasik
09.04.2008, 14:44
Алгоритм перевода вещественных чисел я знаю. Я просто хотел отделить целую и дробную часть для отдельного преобразования. Меня сейчас интересует как при загрузке числа в регистр я могу дойти до запятой, остановиться и отделить целую и дробную часть.

Pegasik
09.04.2008, 15:05
Насчёт FPU, никогда его не использовал, если есть другой вариант, подскажите пожалуйста, а если нет, примерчик использования FPU подкиньте.

somewhere
09.04.2008, 16:14
Перевести в двоичную можно по-другому, если почитать про формат действительных чисел. Все они основаны на правиле Мантисса*2^Экспонента. Все числа имеют один знаковый бит, биты экспоненты и мантиссы варьируются в зависимости от разрядности действительного числа (32,64 или 80 бит), но обычно никто в это не вникает и делают чисто математически используя FPU.
Отделение целой и дробной части:


YourNumber dd 27.32 ; ну например ))
YourIntValue dd ? ; Здесь будет целая
YourFracValue dd ? ; А здесь дробная часть
FPUCW dw ? ; тута управляющее слово
..... тра-ля-ля .....
..... туда-сюда .....
fnstcw FPUCW ; перепишем управляющее слово
fwait ; подождем пока он подумает
or FPUCW, 0F00h ; включим бит, теперь округление всегда к нулю
fldcw FPUCW ; закинем его обратно
fwait ; еще потупим немного
fld YourNumber ; грузим число
fist YourIntValue ; запишем его целую часть, начинает работать порядок округления
fisub YourIntValue ; вычитаем из числа его целую часть
fabs ; берем модуль, получили дробную часть
fstp YourFracValue ; выгружаем ее

Pegasik
09.04.2008, 16:38
Спасибо за исчерпывающий ответ, но наверно для начала надо серьёзно почитать про работу с FPU