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

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

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 28.01.2023, 15:35   #1
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию Как такой программой вывести число типа байт?

Код:
.model small ;Объявляем модель программы
data segment ;объявляем начало сегмента данных с помощью ключевого слова "segment"
n dw 0 ;результирующее число
String db 8 dup (" ") ;исходная строка
Array db 6 dup(?),'$'
data ends ;конец сегмента данных
stk segment stack ; объявление сегмента стека
db 256 dup(" ") ; объем стека
stk ends ; конец стека
code segment ;объявляем начало сегмента кода с помощью ключевого слова "segment"
assume cs: code, ds: data, ss: stk ; assume нужно для того, чтобы связать сегменты прописанные
в коде с сегментами ассемблера *обязательно*
start:
mov ax, data ; занесение адреса сегмента
mov ds, ax ; данных в регистр сегмента данных, *обязательно*
;ввод строки и ее преобразование в число:
mov ah, 3fh ;вводим число в виде набора символов
mov bx, 0
lea dx, String
int 21h ;регистр ax будет содержать количество введенных символов +2
mov di, ax ;сохраняем количество введенных символов в di
sub di, 3 ;находим позицию последнего символа
mov cx, 1 ;
Convert:
cmp String[di], '-' ;сравниваем первый символ с символом '-'
je TurnsNegative
mov ax, 0 ;ax обнуляется
mov al, String[di] ;копируем символ, на который показывает di, в al
sub ax, 30h ;преобразуем символ в число (цифру)
mul cx ;умножаем полученное число на cx (данный регистр сейчас используется как
множитель на 10
add n, ax ;добавляем полученное число в n (результат)
mov bl, 0Ah ;помещаем в bl число 10, чтобы умножить регистр сx на это число
mov ax, cx ;копируем cx в ax для того, чтобы его умножить
mul bl ;умножаем ax на bx
mov cx, ax ;результат сохраняем в cx
dec di ;сдвигаем позицию индекса на один разряд влево
cmp di, 0 ;проверяем, преобразованы ли все символы, кроме первого,
;который может содержать знак числа
jge Convert
jmp Continue
TurnsNegative: neg n
;вывод числа:
Continue:
mov ax, n
;число может быть отрицательным или положительным
push ax ;Ложим ax в стек, чтобы в последствии проверить его знак.
mov si, 10 ;делитель для выделения младшего разряда
;проще говоря, помещаем основание системы счисления
mov di, 5 ;максимально число типа dw может занимать 6 позиций(включая знак).
mov dx, 0 ;dx=0, так как (dx:ax)/si (так как на si мы собираемся делить
cmp ax, 0 ;проверяем знак числа
;если число положительное, переходим на метку NumberToArray
jge NumberToArray
;если число отрицательное, меняем знак
neg ax
NumberToArray:
div si ;значение из (dx:ax) делим на 10, выделяя последний разряд
;числа, который помещается в регистр dx. Так как это число
;не будет больше, чем 9, оно помещается в dl (остаток от деления)
;по сути мы просто выводим остаток от деления на систему счисления
add dl, 30h ;преобразуем полученную цифру в символ (см таблицу ASCII для MSDOS)
mov Array[di], dl ;вставляем полученный символ в строку результата
dec di ;сдвигаем позицию указателя в строке влево
mov dl, 0 ;очищаем dl (где находится остаток от деления)
cmp ax, 0 ;проверяем, преобразованы ли все символы числа
jne NumberToArray ;если преобразованы не все символы, возвращаемся
;на начало цикла
IsNegative:
pop ax ;если всё число преобразовано, извлекаем первоначальное
;значение из стека для проверки знака
cmp ax, 0 ;проверяем знак числа
jge OutputArray ;если число >0, переходим на метку OutputArray (вывод строки)
mov Array[di], '-' ;если число отрицательное, перед числом вставляем знак '-'
OutputArray:
mov ah, 09 ;вывод строки, содержащей преобразованное число
lea dx, Array
int 21h
EndOfProgram:
mov ah, 4ch ; Помещение номера процедуры для выхода из программы в регистр ah
int 21h ; Выполняет процедуру, номер которой находится в регистре ah
code ends ;конец сегмента кодов
end start
alonil вне форума Ответить с цитированием
Старый 28.01.2023, 15:47   #2
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию

Дело вот в чем.Это пример из методички.Я хотел его изменить ,чтобы он работал для числа типа db.Но он сразу у меня перестает работать.Это я для себя.Хотел научится и потренироватся преобразовавать строку в число и обратно.Искал в Интернете ,но точно такого примера нигде нет,а мне нужен именно он,а не другие реализации .Пожалуйста,скиньте переделку этого кода под тип числа db.
alonil вне форума Ответить с цитированием
Старый 28.01.2023, 18:54   #3
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Тут написана какая-то муть. Во-первых, если у вас число размером в byte тогда оно содержит не более 3-х разрядов. Но вы просто переходите к символу строки с индексом 3 (4-му разряду), не учитывая, что числа от 0 до 99 короче, чем 3 знака. Во-вторых, зачем вы умножаете числа и множитель?

В целом для перевода чисел различных размеров из строки не нужно много функций. Достаточно одной универсальной и функции проверки диапазонов т.к. в любых диапазонах бинарные числа представляются одинаково.
Код:
db                         01000110b ; 70
dw                 0000000001000110b ; 70
dd 00000000000000000000000001000110b ; 70

db                         10111010b ; -70
dw                 1111111110111010b ; -70
dd 11111111111111111111111110111010b ; -70
Как видите в первом случае старшие разряды все состоят из 0 (для положительных чисел и 0), а во втором случае - 1 (для отрицательных чисел). Тогда, чтобы уместить число в переменной нужного размера его необходимо расширить или усечь заполняя старшие байты соответствующими значениями бит. Более того
Код:
            01000110b ; 70
инвертируем 10111001b
плюс один   10111010b ; -70 - это число представлено в дополнительном коде

Проверяем
 00000000b ; 0
-01000110b ; вычитаем 70
 10111010b ; результат -70
Последовательности этих чисел можно получить таким не хитрым образом.

Теперь попробуем написать перевод чисел из строки, в которой записано число в 10-ой системе счисления
Код:
    mov ax, 0 ; dx:ax - начальное значение
    mov dx, 0
    mov cx, 10 ; основание системы счисления
    lea si, [string] ; строка для перевода числа

convert_loop: ; цикл перевода символов строки
; проверяем наличие в строке следующей цифры числа
    cmp byte ptr [si], '0'
    jc end_of_number
    cmp byte ptr [si], '9'
    ja end_of_number
; Теперь точно известно, что в числе есть еще один разряд
; Добавляем в буфер (dx:ax) еще один разряд (младший)
; Для этого необходимо имеющие разряды числа умножить на основание системы счисления
; После умножения младший разряд равен 0 и при сложении с разрядом переведенным из строки переполнения (переноса в старший разряд) не возникнет
    mov di, ax ; Сохранили младшие разряды числа в в di
    mov ax, dx ; Будем сначала умножать старшие разряды
    mul cx ; Умножили значение dx*10
    test dx, dx ; Если появились разряды отличные от 1 в dx, тогда число уже не умещается в 32-бита
    jnz int_overflow ; переходим на метку int_overflow, если число не умещается в 32-бита
    xchg ax, di ; Теперь в ax младшие разряды числа, а в di сохранили старшие разряды уже умноженные на 10
    mul cx ; Умножили значение ax*10
    mov bl, [si] ; Переводим символ строки в цифру ...
    sub bl, '0' ; ... путем вычитания кода '0'
    inc [si] ; Переходим к следующему разряду числа
    mov bh, 0 ; и расширяем цифру до 16-бит, чтобы сложить ее значение с ax
    add ax, bx ; Вычисляем значение dx:ax * 10 + цифра
    adc dx, di ; Старшие разряды складываем уже с учетом флага переноса из младших разрядов
    jnc convert_loop ; Повторяем цикл пока не возникнет переноса из старшего разряда (int_overflow)

int_overflow: ; Здесь необходимо обработать случай, когда число не умещается в буфере
    xor ax, ax
    xor dx, dx
    jmp quit

end_of_number: ; А это случай для завершения цикла перевода и выдачи числа
; Тут еще можно проверить записанное в строке (возможно в строке не верная запись числа)
; Переведенное число находится в паре регистров dx:ax
; Для записи их в переменную типа db необходимо, чтобы значение укладывалось в диапазон -128 .. 127
; Для записи их в переменную типа dw необходимо, чтобы значение укладывалось в диапазон -32768 .. 32767
; Для записи их в переменную типа dd уже все готово, но запись надо выполнять по частям т.к. значение находится в паре регистров
В общем виде число в N системе счисления представляется так Ak*N^k + Ak-1*N^(k-1) + ... + A1*N^1 + A0*N^0
У вас в алгоритме как раз пытаются вычислять это выражение, но зачем. Давайте его немного перепишем. С точки зрения записи выражение станет сложнее (куча вложенных скобок, с которыми легко запутаться). Но с точки зрения реализации в программе все станет легче (см. мой вариант)
((...(Ak * N + Ak-1)*N + ...)*N + A1)*N+A0
Во втором случае вам не надо вычислять постоянно N^x, что сразу упрощает реализацию.

Последний раз редактировалось macomics; 28.01.2023 в 20:16.
macomics вне форума Ответить с цитированием
Старый 28.01.2023, 19:02   #4
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию

Спасибо большое.
alonil вне форума Ответить с цитированием
Старый 28.01.2023, 19:06   #5
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Теперь обратное преобразование (из числа в строку). Здесь тоже не нужно много вариантов программ, но какие-то отдельные реализации можно сделать отдельно. Например для db т.к. для этого числа достаточно 2-х операций деления
Код:
    lea di, [buffer]
    mov al, 126 ; Начальное значение (переводимое)

; Этот блок можно опустить для чисел без знака
    test al, al ; Проверяем знак числа
    jns unsigned_int ; Если число положительное, тогда переходим к переводу
    mov byte ptr [di], '-' ; Добавляем в строку знак минус т.к. число отрицательное
    neg al ; Вычисляем значение по модулю
    inc di ; Пропускаем знак минус записанный в строку

unsigned_int:
    mov cx, 10 ; Основание системы счисления
    cbw ; Расширяем байт до слова (только для знаковых чисел). Для без знаковых надо использовать команду mov ah, 0. Но в обоих случаях будут разные команды.
    div cx ; ax = старшие два разряда числа; dx = младший
    div cl ; ah = средний разряд числа; al = старший
; Как видите, если написать так, то не нужно даже циклов
; Теперь эти разряды предстоит проверить и записать в строку
; Проверяем оба старших разряда на равенство 0
    mov dh, al
    add dh, ah
    jz one_digit_munber
; Проверяем старший разряд на равенство 0
; Числа 127 .. 100
    cmp al, 0
    jz two_digit_munber
    add al, '0'
    mov byte ptr [di], al
    inc di

two_digit_munber:
; числа 10 .. 99
    add ah, '0'
    mov byte ptr [di], ah
    inc di

one_digit_number:
; Числа 0 .. 9
    add dl, '0'
    mov byte ptr [di], dl
    inc di

Последний раз редактировалось macomics; 28.01.2023 в 19:29.
macomics вне форума Ответить с цитированием
Старый 28.01.2023, 19:17   #6
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Но числа длиннее байта лучше переводить с использованием циклов
Код:
    lea di, [buffer] ; Строка для перевода числа
    mov dx, number_high ; Начальное значение числа расширенное до 32-бит
    mov ax, number_low
    mov cx, 10 ; Основание системы счисления для перевода

; Этот блок можно опустить для чисел без знака
    test dx, dx ; Проверяем знак числа
    jns unsigned_int ; Если число положительное, тогда переходим к переводу
    mov bx, ax ; Сохраняем число в двух других регистрах
    mov si, dx
    mov byte ptr [di], '-' ; Добавляем в строку знак минус т.к. число отрицательное
    xor ax, ax ; Обнуляем dx:ax
    xor dx, dx
    inc di ; Пропускаем знак минус записанный в строку
    sub ax, bx ; Вычитаем из 0 начальное значение (вычисляем значение по модулю т.к. число отрицательное)
    sbb dx, si

unsigned_int:
    mov si ,sp ; Сохраняем значение sp для второго цикла

convert_loop: ; Этот цикл разобьет число на отдельные разряды, которые будут убраны в стек
    mov bx, ax ; Сохраняем младшую часть числа в bx
    mov ax, dx ; Делим сначала старшую часть числа на основание системы счисления (остаток - это разряды для деления младшей части числа)
    cbw ; Расширяем число до 48-бит
    div cx ; Делим
    xchg bx, ax ; Сохраняем частное в bx и готовим значение для деления младшей части числа
; В dx остаток от деления старшей части числа. Его не надо трогать, чтобы результат деления был верным
    div cx ; Делим
    add dl, '0' ; Переводим остаток от деления в символ
    push dx ; И сохраняем символ в стек (это необходимо, чтобы развернуть число в обратном порядке)
    mov dx, bx ; Кладем на место значение старшей части числа
    add bx, ax ; Проверяем число на 0 (цикл будет продолжаться до достижения 0)
    jnz convert_loop ; Число еще не равно 0, продолжаем

    cld ; Чтобы символы в строку складывались в нужном порядке
save_loop: ; Достаем символы из стека и сохраняем их в строке
    pop ax ; Достали символ из стека
    stosb ; Сохранили его в строке
    cmp sp, si ; Проверили стек на заполнение символами
    jc save_loop ; В стеке еще есть символы, продолжаем цикл
; Результат записан в строку

Последний раз редактировалось macomics; 28.01.2023 в 19:36.
macomics вне форума Ответить с цитированием
Ответ


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

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

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


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[C++] Проблемы с программой. Дано целое число N (> 1). Вывести наименьшее целое K, при котором выполняется неравенство 3K > N, и само значение 3K Орлов Помощь студентам 2 11.07.2017 09:29
Delphi. Цикл While. Вывести целые числа от А до В, А вывести 1 раз, число А+1 вывести 2 раза и т.д. schibeki Помощь студентам 4 07.02.2014 09:17
как сделать из числа типа real число типа integer? gylayko Помощь студентам 6 15.09.2012 11:41
Написать программу, исх. данные типа байт Garik2277 Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 2 01.02.2011 00:25