Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.191.208.203] |
|
Сообщ.
#1
,
|
|
|
Здраствуйте. Нужно чтоб программа отображала на экране любое введенное целое число в восьмиричной системе счисления.
Возникла проблема - не понимаю как записать, чтоб пользователь мог вводить любое число. Да и исходник не уверена что правильный. Вобщем кто разбирается подкоректируйте его пожалуйта. Буду очень благодарна! Исходник: .MODEL Small .STACK 100h .DATA String db 16 dup (?),'$' ; Резервируем 16 байт для строки StringEnd = $-1 ; Указывает на символ '$' Number = 1 Str_digit db '5.479$' Obrob_digit db 8 dup (?),'$' ; Drob_chast db 8 dup (?),'$' 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 - ", " $" Mes_4 db 0dh, 0ah, "Chislo 0.479 v 16-y sisiteme schisleniya - ", " $" .CODE ORG 100h Start: mov ax,@data mov ds,ax mov es,ax mov ch,16 lea dx,Mes_4 mov ah,09h int 21h call Razdel mov ah,09h lea dx,Obrob_digit int 21h ; mov ah,09h ; lea dx,Drob_chast ; int 21h ; mov ax,dx ; mov bx,16 ; jmp Proverka_num call Perevod 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 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 |
Сообщ.
#2
,
|
|
|
Помогите пожалуйсто!
|
Сообщ.
#3
,
|
|
|
Лови, Deffi.
Все за тебя делать не стал, но ввод и преобразование строки в число показал. Компилируй и линкуй: tasm /zn filename.asm tlink filename.obj По ссылке Сложение чисел посмотри. Там немного прокомментирован перевод числа в десятичное представление. Восьмеричное - почти то же самое, только основание системы - 8. Для ввода строки я использовал функцию DOS 0Ah. Она вводит в буфер следующего формата: 0-й байт - максимально вводимое число символов + 1 (на символ перевода строки - CR) 1-й байт - по возвращении из int 21h здесь будет длина введенной строки (без учета CR) 2-й байт - начало буфера ввода, его длина равна числу в 0-м байте. Т.к. максимальное число, умещающееся в слове (двух байтах) равно 65535, то длину буфера я выбрал равной 5+1=6 байтам. .MODEL Small .DATA KeyBuf db 6, 0, 6 dup(0) ;max,len,string,CR(0dh) CR_LF db 0Dh, 0Ah, '$' Prompt db 'Введите число: ', '$' Res10 db 'Введено число (десятичное ): ', '$' Res08 db 'Введено число (восьмеричное): ', '$' Error01 db 'Ошибка ввода числа',0Dh, 0Ah, '$' Numer dw ? .CODE ; выводит число в регистре AX на экран ; входные данные: ; cx - система счисления (не больше 10) ; ax - число для отображения Show_ax PROC ; mov cx, 10 xor di, di ; di - кол. цифр в числе @@Conv: xor dx, dx div cx ; dl = num mod 10 add dl, '0' ; перевод в символьный формат inc di push dx ; складываем в стэк or ax, ax jnz @@conv ; выводим из стэка на экран @@Show: pop dx ; dl = очередной символ mov ah, 2 ; ah - функция вывода символа на экран int 21h dec di ; повторяем пока di<>0 jnz @@show ret Show_ax ENDP ; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; ds:[di] - адрес числа ; на выходе ; ds:[di] - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num PROC push ax push bx push cx push dx push ds push es push ds pop es mov cl, ds:[si] xor ch, ch inc si mov bx, 10 xor ax, ax @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; игнорируем старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@Error cmp al, '9' ja @@Error sub al, '0' xor ah, ah add ax, [di] inc si loop @@Loop mov [di], ax clc pop es pop ds pop dx pop cx pop bx pop ax ret @@Error: xor ax, ax mov [di], ax stc pop es pop ds pop dx pop cx pop bx pop ax ret Str2Num ENDP Main PROC FAR mov ax, @DATA mov ds, ax mov es, ax ; ввод числа с клавиатуры (строки) lea dx, Prompt mov ah,09h int 21h mov ah, 0Ah mov dx, offset KeyBuf int 21h ; перевод строки (на новую строку) lea dx, CR_LF mov ah,09h int 21h ; преобразование строки в число lea si, KeyBuf+1 lea di, Numer call Str2Num ; проверка на ошибку jnc @@NoError ; если есть ошибка ввода - напечатать сообщение об ошибке lea dx, Error01 mov ah,09h int 21h jmp @@Exit ; если нет ошибки ввода - напечатать число @@NoError: ; в десятичном представлении lea dx, Res10 mov ah,09h int 21h mov ax, Numer mov cx, 10 call Show_ax lea dx, CR_LF mov ah,09h int 21h ; в восьмеричном представлении lea dx, Res08 mov ah,09h int 21h mov ax, Numer mov cx, 8 call Show_ax lea dx, CR_LF mov ah,09h int 21h ; выход @@Exit: mov ax,4c00h int 21h Main ENDP .STACK 100h END Main |
Сообщ.
#4
,
|
|
|
Заметил у себя ошибку. Если ввести число 65536, то результат будет равен 0. А должно быть сообщение об ошибке.
Нужно добавить строку в процедуру Str2Num add ax, [di] jc @@Error ; Если сумма больше 65535 inc si loop @@Loop |
Сообщ.
#5
,
|
|
|
Спасибо огромное Павел. У тебя есть аська, а то есть вопросы, чтоб тут не флудить.
|
Сообщ.
#6
,
|
|
|
К сожалению, нет . Задавай на форуме. И ведь я не один.
|
Сообщ.
#7
,
|
|
|
Ну ладно, тогда вопрос первый как работает твоя программа? Скомпилила и слинковала. Запускаю ехе файл, черный пустой экран, ввожу любое число программа закрывается и все.
|
Сообщ.
#8
,
|
|
|
Цитата Запускаю ехе файл, черный пустой экран Чуть позже я подкорректировал исходник. Добавил "приглашение" - 'Введите число: ' ; ввод числа с клавиатуры (строки) lea dx, Prompt mov ah,09h int 21h Цитата Скомпилила и слинковала. Запускаю ехе файл .... ввожу любое число программа закрывается и все. Добавь в конце после метки @@Exit ввод любой клавиши @@Exit: ; ожидание нажатия любой клавиши mov ah,01h int 21h mov ax,4c00h int 21h Main ENDP Вот мой exe-шник Прикреплённый файлInput_D.zip (1.83 Кбайт, скачиваний: 144) |
Сообщ.
#9
,
|
|
|
Приглашение действительно появилось, а вот когда добавила в конце после метки @@Exit ввод любой клавиши - все равно экзешник закрывается при вводе числа.
Скачала файл Input_D.zip, а чем открыть сам файл, он у тебя там без разширения? |
Сообщ.
#10
,
|
|
|
Сейчас еще раз проверил - в архиве два файла Input_D.asm и Input_D.exe. Input_D.asm в кодировке DOS. Input_D.exe запускается и в конце ждет нажатия. Т.е. работает. Покажи еще раз свою программу. Может быть вместо int 21h выполняется int 21 ?
А какой файл в архиве без расширения? Там один exe-шник, другой asm. Сам архив открывается WinZip'ом или WinRar'ом. .MODEL Small .DATA KeyBuf db 6, 0, 6 dup(0) ;max,len,string,CR(0dh) CR_LF db 0Dh, 0Ah, '$' Prompt db 'Введите число: ', '$' Res10 db 'Введено число (десятичное ): ', '$' Res08 db 'Введено число (восьмеричное): ', '$' Error01 db 'Ошибка ввода числа',0Dh, 0Ah, '$' Numer dw ? .CODE ; выводит число в регистре AX на экран ; входные данные: ; cx - система счисления (не больше 10) ; ax - число для отображения Show_ax PROC ; mov cx, 10 xor di, di ; di - кол. цифр в числе @@Conv: xor dx, dx div cx ; dl = num mod 10 add dl, '0' ; перевод в символьный формат inc di push dx ; складываем в стэк or ax, ax jnz @@conv ; выводим из стэка на экран @@Show: pop dx ; dl = очередной символ mov ah, 2 ; ah - функция вывода символа на экран int 21h dec di ; повторяем пока di<>0 jnz @@show ret Show_ax ENDP ; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; ds:[di] - адрес числа ; на выходе ; ds:[di] - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num PROC push ax push bx push cx push dx push ds push es push ds pop es mov cl, ds:[si] xor ch, ch inc si mov bx, 10 xor ax, ax @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; игнорируем старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@Error cmp al, '9' ja @@Error sub al, '0' xor ah, ah add ax, [di] jc @@Error ; Если сумма больше 65535 inc si loop @@Loop mov [di], ax clc pop es pop ds pop dx pop cx pop bx pop ax ret @@Error: xor ax, ax mov [di], ax stc pop es pop ds pop dx pop cx pop bx pop ax ret Str2Num ENDP Main PROC FAR mov ax, @DATA mov ds, ax mov es, ax ; ввод числа с клавиатуры (строки) lea dx, Prompt mov ah,09h int 21h mov ah, 0Ah mov dx, offset KeyBuf int 21h ; перевод строки (на новую строку) lea dx, CR_LF mov ah,09h int 21h ; преобразование строки в число lea si, KeyBuf+1 lea di, Numer call Str2Num ; проверка на ошибку jnc @@NoError ; если есть ошибка ввода - напечатать сообщение об ошибке lea dx, Error01 mov ah,09h int 21h jmp @@Exit ; если нет ошибки ввода - напечатать число @@NoError: ; в десятичном представлении lea dx, Res10 mov ah,09h int 21h mov ax, Numer mov cx, 10 call Show_ax lea dx, CR_LF mov ah,09h int 21h ; в восьмеричном представлении lea dx, Res08 mov ah,09h int 21h mov ax, Numer mov cx, 8 call Show_ax lea dx, CR_LF mov ah,09h int 21h ; выход @@Exit: ; ожидание нажатия любой клавиши mov ah,01h int 21h mov ax,4c00h int 21h Main ENDP .STACK 100h END Main |
Сообщ.
#11
,
|
|
|
Я скачала вот этот архив, Input_D.zip (1.83 кб) открыла WinRar и у меня там один файл Input_D без разширения и все больше ничего нет.
В Tasm можно как-то сделать поддержку русского языка, а то у меня текст крякозяблами отображается? И по поводу экзешника, открываю его появляется приглашения ввода числа, ввожу любое число (экзешник уже не закрывается после ввода) но результаты странные, ввожу число например 64, результат в восьмеричной системе этого числа 8 (правильно я понимаю?) , а появляется в результате 100. Я скриншот прикрепляю, посмотри пожалуйсто. Прикреплённый файлСкриншот.png (15.88 Кбайт, скачиваний: 225) |
Сообщ.
#12
,
|
|
|
Цитата Deffi @ Сама добавь расширение распакованному файлу Input_D, например ZIP, или RAR. И распакуй еще раз Я скачала вот этот архив, Input_D.zip (1.83 кб) открыла WinRar и у меня там один файл Input_D без разширения и все больше ничего нет. Цитата Deffi @ Ну так это и есть правильный результат.ввожу число например 64, результат в восьмеричной системе этого числа 8 (правильно я понимаю?) , а появляется в результате 100 Цитата Deffi @ В тасме нельзя Тебе нужно русификатор установить, для DOS-сессии. В Tasm можно как-то сделать поддержку русского языка, а то у меня текст крякозяблами отображается? |
Сообщ.
#13
,
|
|
|
Для избавления от кракозябр, нужно текст программы на ассемблере сконвертировать из кодировки Win(1251) в кодировку DOS(866), а затем скомпилировать. Полученный exe-шник будет "говорить по-русски".
Перекодировку можно сделать текстовым редактором AkelPad (скачать можно по ссылке AkelPad объем примерно 25 кБайт) из меню "Кодировки"-"Сохранить в DOS-866". А результат в восьмеричной системе можно проверить в Windows-ком калькуляторе. Пункт меню "Вид" - Инженерный. Набрать число в десятичной системе - Dec, а потом переключиться в восьмеричную систему - Oct. Очень наглядно видно, что 6410=1008. Добавлено Сейчас немного "погулял" по форуму, встретил несколько ссылок по системам счисления: Системы счисления. перевода чисел в другую систему счислени |
Сообщ.
#14
,
|
|
|
; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; ds:[di] - адрес числа ; на выходе ; ds:[di] - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num PROC push ax ; сохранение используемых регистров при входе в подпрограмму push bx push cx push dx push ds push es push ds ; регистр es=ds - случайно остались две строки :) - можно удалить pop es mov cl, ds:[si] ; для цикла LOOP устанавливаем счетчик - т.е. сколько xor ch, ch ; символов в строке нужно обработать inc si ; переходим к первому символу в строке (ds:si - содержит адрес) mov bx, 10 ; множитель для каждой цифры xor ax, ax ; начальное значение результата приравниваем к нулю @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; сохраняем результат, игнорируя старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' ; проверяем на то, что в al находится символ цифры от '0' до '9' jb @@Error ; если не символ цифры - тогда ошибка cmp al, '9' ja @@Error sub al, '0' xor ah, ah ; в ax сейчас число соответствующее цифре add ax, [di] ; сложить цифру (ax) с текущим результатом jc @@Error ; Если сумма больше 65535 inc si ; перейти к адресу следующего символа цифры loop @@Loop mov [di], ax ; сохранить результат clc ; сбросить флаг CY - ошибки нет pop es ; восстановить регистры pop ds pop dx pop cx pop bx pop ax ret @@Error: xor ax, ax ; в случае ошибки записать результат равным нулю mov [di], ax stc ; и установить флаг переноса CY - ошибка при преобразовании строки pop es ; восстановить регистры pop ds pop dx pop cx pop bx pop ax ret Str2Num ENDP Идея примерно следующая: На входе имеется 1) адрес строки в формате: длина_строки (1 байт), строка (несколько байт); 2) адрес, по которому будет находиться результат (2 байта). После завершения подпрограммы 1) если сброшен бит CY (переноса), то по второму адресу будет записано число, соответсвующее строке; 2) если флаг CY установлен, то значит во время преобразования произошла ошибка (или результат должен был быть больше 65535, или в строке присутствовали не только цифры но и лишние символы). Давай посмотрим по шагам для строки '987'. При входе в п/п ds:si указывает на строку db 3, '987' (si=адресу ячейки памяти с числом 3) Перед входом в цикл LOOP после всех присвоений имеем cx=3, ax=0, ds:si - равен адресу символа '9', bx=10. Вошли в цикл. dx:ax=ax*bx=0*10=0 (т.е. dx=0 и ax=0) Записали в результат значение ax - ds:[di]=ax=0 Проверяем на переполнение (результат не превышает 65535 - т.е. dx должен быть равен 0) - все в порядке. По адресу ds:[si] считываем в al символ цифры (mov al, [si]) - al='9'. Проверяем, чтобы '0' <= al <= '9' - да, условие выполняется. Из al вычитаем число, соответствующее коду символа '0' - теперь al=9 (и ax=9). Складываем с результатом (по адресу ds:[di]) - ax=0+9=9. Проверяем, не было ли переполнения при сложении (число больше 65535) - нет не было. Адрес указателя ds:si увеличиваем на 1 - теперь в ds:[si] адрес символа '8' - это для следующего прохода. Оператор loop вычитает из cx единицу и проверяет cx=0? Нет cx=cx-1=3-1=2 <> 0. Переход к метке @@Loop. Дальше для ускорения описания пропущу проверки. Снова проходим цикл с метки @@Loop. dx:ax=ax*bx=9*10=90. Результат (ds:[di]) приравниваем к ax=90. Считываем в al символ из адреса ds:[si] - т.е. al='8' Вычитаем из al код символа '0' - al=8 (ax=8). Складываем с результатом (по адресу ds:di) - ax=90+8=98. Адрес указателя ds:si увеличиваем на 1 - теперь в ds:[si] адрес символа '7' - это для следующего прохода. Оператор loop вычитает из cx единицу и проверяет cx=0? Нет, cx=cx-1=2-1=1 <> 0. Переход к метке @@Loop. Снова проходим цикл с метки @@Loop. dx:ax=ax*bx=98*10=980. Результат (ds:[di]) приравниваем к ax=980. Считываем в al символ из адреса ds:[si] - т.е. al='7' Вычитаем из al код символа '0' - al=7 (ax=7). Складываем с результатом (по адресу ds:di) - ax=980+7=987. Адрес указателя ds:si увеличиваем на 1 - теперь в ds:[si] адрес за символом '7' - хоть и некорректный, но это ведь последний проход цикла. Оператор loop вычитает из cx единицу и проверяет cx=0? Да, cx=cx-1=1-1=0 == 0. Переход к следующему за Loop оператору. По адресу ds:[di] записывается содержимое ax=987. Сбрасывается флаг переноса CY - нет ошибки преобразования. Восстанавливаются регистры (их содержимое теперь равно тому, что было перед входом в подпрограмму) - это можно делать, т.к. результат возвращается не в регистре, а в памяти по адресу ds:[di]. Если на вход подпрограммы подать некорректные данные, то во время одной из проверок произойдет переход на метку @@Error. Тогда там обнуляется регистр ax (xor ax, ax) и значение ax (т.е. ноль) записывается в ds:[di]. А также устанавливается признак ошибки - флаг переноса CY. Потом восстанавливаются регистры. В общем, весь алгоритм напоминает схему Горнера - ( 9*10 + 8 )*10 + 7 = 987. "Несколько" коряво, но вроде бы понятно (надеюсь)... У-ух. Набрал... |
Сообщ.
#15
,
|
|
|
Спасибо, Павел! Столько набрал, я даже не ожидала
Если возникнут еще вопросы я напишу сюда, хотя врядли после такого подробного коментария. P.S С НОВЫМ ГОДОМ! Желаю тебе крепкого здоровья, удачи, финансового благополучия, ну и чтоб все то добро, которое ты делаешь другим людям вернулось тебе в трехкратном размере ! |
Сообщ.
#16
,
|
|
|
Сообщ.
#17
,
|
|
|
Кстати, а как переводятся отрицательные числа ?
|
Сообщ.
#18
,
|
|
|
Для вывода отрицательных чисел нужно добавить строки в процедуру Show_ax, проверяющие знак числа. В случае отрицательного числа нужно вывести знак минус "-", и преобразовать число в регистре ax.
; если число в ax отрицательное, то ;1) напечатать '-' ;2) сделать ax положительным or ax, ax jns @@Conv push ax mov dx, '-' mov ah, 2 ; ah - функция вывода символа на экран int 21h pop ax neg ax В итоге это будет выглядеть ; выводит число в регистре AX на экран ; входные данные: ; cx - система счисления (не больше 10) ; ax - число для отображения Show_ax PROC ; mov cx, 10 xor di, di ; di - кол. цифр в числе ; если число в ax отрицательное, то ;1) напечатать '-' ;2) сделать ax положительным or ax, ax jns @@Conv push ax mov dx, '-' mov ah, 2 ; ah - функция вывода символа на экран int 21h pop ax neg ax @@Conv: xor dx, dx div cx ; dl = num mod 10 add dl, '0' ; перевод в символьный формат inc di push dx ; складываем в стэк or ax, ax jnz @@conv ; выводим из стэка на экран @@Show: pop dx ; dl = очередной символ mov ah, 2 ; ah - функция вывода символа на экран int 21h dec di ; повторяем пока di<>0 jnz @@show ret Show_ax ENDP Для ввода, нужно добавить строки в процедуре Str2Num 1) перед началом цикла преобразования проверить - первый символ равен '-'. Если равен, то перейти к следующему символу (inc si) 2) после завершения преобразования (а пока что преобразовалось число без учета знака), ещё раз проверить самый первый символ на равенство '-'. Если равен, то нужно выполнить преобразование (neg ax), перед сохранением результата в памяти (mov [di], ax). Еще, желательно, перед сохранением результата выполнить проверку - если результат не соответствует знаку, то это указывает на ошибку (в два байта помещаются числа из диапазона -32768...32767 и если преобразовывать, например, число +32768, то результат будет -32768). |
Сообщ.
#19
,
|
|
|
Немного помудрил...
Нужно увеличить буфер ввода на один символ ("-32768" длиной 6 символов) KeyBuf db 7, 0, 7 dup(0) ;max,len,string,CR(0dh) Str2Num получилась такая ; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; ds:[di] - адрес числа ; на выходе ; ds:[di] - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num PROC push ax push bx push cx push dx push ds push es push si push ds pop es mov cl, ds:[si] xor ch, ch inc si mov bx, 10 xor ax, ax ;если в строке первый символ '-' ; - перейти к следующему ; - уменьшить количество рассматриваемых символов cmp byte ptr [si], '-' jne @@Loop inc si dec cx @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; игнорируем старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@Error cmp al, '9' ja @@Error sub al, '0' xor ah, ah add ax, [di] jc @@Error ; Если сумма больше 65535 js @@Error ; Если результат стал отрицательным inc si loop @@Loop pop si ;проверка на знак push si inc si cmp byte ptr [si], '-' jne @@StoreRes neg ax @@StoreRes: mov [di], ax clc pop si pop es pop ds pop dx pop cx pop bx pop ax ret @@Error: xor ax, ax mov [di], ax stc pop si pop es pop ds pop dx pop cx pop bx pop ax ret Str2Num ENDP Здесь добавились строки 1) перед циклом преобразования ;если в строке первый символ '-' ; - перейти к следующему ; - уменьшить количество рассматриваемых символов cmp byte ptr [si], '-' jne @@Loop inc si dec cx 2) после цикла преобразования pop si ;проверка на знак push si inc si cmp byte ptr [si], '-' jne @@StoreRes neg ax @@StoreRes: 3) внутри цикла преобразования js @@Error ; Если результат стал отрицательным 4) Чтобы была возможность просмотреть первый символ, нужно в начале процедуры сохранить si, а в конце процедуры извлечь из стека (в обоих случаях завершения - правильном и ошибочном). Т.е. идея следующая. 1) Если в строке символ "-", то его поначалу пропускаем и получаем положительный результат. 2) Потом опять проверяем исходную строку на наличие "-". Если он есть, то делаем результат отрицательным (neg ax). 3) Таким образом, во время выполнения преобразования временный результат все время должен быть положительным (флаг знака S - сброшен) - это и есть проверка внутри цикла. |
Сообщ.
#20
,
|
|
|
Сейчас еще раз потестировал - нашел ошибку. Не вводиться число -32768.
Нужно заменить строку js @@Error ; Если результат стал отрицательным на строки cmp ax, 8000h ja @@Error И еще добавить проверку для случая 32768. В целом Str2Num Str2Num PROC push ax push bx push cx push dx push ds push es push si push ds pop es mov cl, ds:[si] xor ch, ch inc si mov bx, 10 xor ax, ax ;если в строке первый символ '-' ; - перейти к следующему ; - уменьшить количество рассматриваемых символов cmp byte ptr [si], '-' jne @@Loop inc si dec cx @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; игнорируем старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@Error cmp al, '9' ja @@Error sub al, '0' xor ah, ah add ax, [di] jc @@Error ; Если сумма больше 65535 cmp ax, 8000h ja @@Error inc si loop @@Loop pop si ;проверка на знак push si inc si cmp byte ptr [si], '-' jne @@Check ;если должно быть положительным neg ax ;если должно быть отрицательным jmp @@StoreRes @@Check: ;дополнительная проверка or ax, ax ; js @@Error @@StoreRes: ;сохранить результат mov [di], ax clc pop si pop es pop ds pop dx pop cx pop bx pop ax ret @@Error: xor ax, ax mov [di], ax stc pop si pop es pop ds pop dx pop cx pop bx pop ax ret Str2Num ENDP Прикреплённый файлINPUT_2.ZIP (1.74 Кбайт, скачиваний: 152) |
Сообщ.
#21
,
|
|
|
Павел, тогда получается что 100 (Dec) = 144 (Oct) и -100 (Dec) = -144 (Oct) хотя если проверить на инженерном калькуляторе в Excel -100 (Dec) = 7777777634 (Oct) Так вот
Прикреплённый файлСкриншот.png (7.23 Кбайт, скачиваний: 290) |
Сообщ.
#22
,
|
|
|
Deffi
Думаю, что программа считает правильно. Ведь она не не изменяет само значение числа (переменную Number). А только в двух форматах (десятичном и восьмеричном) выводит на экран. И если это число -1448 сложить с числом 1448 должен получиться 0. А "калькулятор" производит преобразование из десятичной в восьмеричную без учета знака. Можешь даже проверить (если не лень). Измени программу - чтобы Str2Num была новая, а Show_ax - старая-беззнаковая. И увидишь такой же результат. |
Сообщ.
#23
,
|
|
|
Немного не поняла твоего пояснения, извини.
Добавлено Программа просто добавляет знак минуса на экран и все, и считает как положительные. |
Сообщ.
#24
,
|
|
|
Нет, Deffi, не просто добавляет.
Обе подпрограммы работают уже с другим форматом данных. При отображении на экран действительно кажется только, что добавляется символ "-". Но так и должно быть. Например, 10010=1448 и -10010=-1448. Все вроде правильно. Но внутреннее представление этих чисел разное. Посмотрим пример: 10010=1448=6416=0000 0000 0110 01002 - вроде понятно -10010=-1448=-6416=-0000 0000 0110 01002 - тоже понятно. Но как в пределах 16-бит найти место для обозначения отрицательных чисел? Разработчики микросхем пошли по следующему пути. Решили, что старший бит будет означать знак минус. Так для чисел осталось 15 бит. Положительные от 0000 0000 0000 00002 до 0111 1111 1111 11112 (от 0 до 32767) и отрицательные от 1111 1111 1111 11112 до 1000 0000 0000 00002 (от -1 до -32368). Отрицательные числа решили сделать в машинном представлении такими, чтобы без дополнительных материальных (в смысле транзисторов внутри процессора) затрат организовать вычисления - т.е. чтобы -1+1=0, как при обычном сложении. Возьмем число 1=0000 0000 0000 00012. Что нужно к нему прибавить, чтобы получился 0=0000 0000 0000 00002? Правильно, 1111 1111 1111 11112=-1. Заметь, что число -1=1111 1111 1111 11112, а не 1000 0000 0000 0001. Такой формат называется "дополнительный код". В дополнительном коде 010=0000 0000 0000 00002 110=0000 0000 0000 00012 210=0000 0000 0000 00102 310=0000 0000 0000 00112 ........................................... 3276710=0111 1111 1111 11112 -110=1111 1111 1111 11112 - в дополнительном коде -210=1111 1111 1111 11102 - в дополнительном коде -310=1111 1111 1111 11012 - в дополнительном коде ............................................. -3276810=1000 0000 0000 00002 - в дополнительном коде Первый вариант программы работал с положительными числами от 0 до 65535 (никаких отрицательных). Поэтому там символ "-" рассматривался как ошибочный. При вводе строки "65535" в переменную Number процедура Str2Num записывала число 1111 1111 1111 11112. Подпрограмма Show_ax преобразовывала число в Number в строку "65535" и выводиоа на экран. Второй вариант программы работает уже форматом чисел в дополнительном коде. Поэтому пришлось изменить процедуры ввода числа и вывода числа. Проще изменения в Show_ax - проверяется знаковый бит, и если он установлен, то сразу же выводится на экран символ "-", а потом инвертируется число (neg ax), т.е. было -10010=-1448=-0000 0000 0110 01002=1111 1111 1001 11002, а стало +10010=+1448=0000 0000 0110 01002. А потом уже это число преобразуется в строку. Все это есть в комментариях. В Str2Num изменений побольше. Еще до начала цикла проверяется строка на сивол "-". Если его нет, то преобразование почти без изменений по сравнению с первым (беззнаковым вариантом) - добавилось лишь ограничение диапазона чисел до 32767. Если же первым в строке стоит символ "-", тогда перед циклом переходим к следующему символу (см. в комментариях). Потом происходит такое же преобразование строки, получаем положительное число. После преобразования еще раз проверяется первый символ в строке, если он "-", тогда число приводится к дополнительному коду (neg ax). В общем, первый вариант программы работал с беззнаковыми числами, а второй со знаковыми в дополнительном коде. Если я не очень хорошо объяснил, почитай в книжках по асму про дополнительный код или в Wiki http://ru.wikipedia.org/wiki/Дополнительный_код_(представление_числа). Из баловства, можешь поэкспериментировать с разными сочетаниями подпрограмм ввода/вывода. При знаковом вводе и беззнаковом выводе будут получаться необычные результаты - как на "калькуляторе": вводим: -100 получаем: 6543610 и 1776348 Вот такой хулиганский файл прилагаю Прикреплённый файлINPUT3.ZIP (1.69 Кбайт, скачиваний: 165) |
Сообщ.
#25
,
|
|
|
Ты так подробно все объясняешь, что и wikipedia нет надобности читать.
У нас даже преподаватели так подробно не объясняют. |
Сообщ.
#26
,
|
|
|
Павел, чесно сказать уже и совесть не позволяет что-либо у тебя еще спрашивать, но может напишешь как сделать, чтоб после ввода пользователем числа экзешник не закрывался автоматически, а только когда я нажму Esc.
Добавлено И еще такой вопрос, немного неясен твой алгоритм, ведь например в математике для перевода десятичного числа в восьмиричное, его нужно последовательно делить на 8 до тех пор, пока не останется остаток, меньше или равен 7, сдесь же ты умножаешь ax*bx "...Вошли в цикл. dx:ax=ax*bx=0*10=0 (т.е. dx=0 и ax=0) Записали в результат значение ax - ds:[di]=ax=0 Проверяем на переполнение (результат не превышает 65535 - т.е. dx должен быть равен 0) - все в порядке. По адресу ds:[si] считываем в al символ цифры (mov al, [si]) - al='9'. Проверяем, чтобы '0' <= al <= '9' - да, условие выполняется. Из al вычитаем число, соответствующее коду символа '0' - теперь al=9 (и ax=9). Складываем с результатом (по адресу ds:[di]) - ax=0+9=9. Проверяем, не было ли переполнения при сложении (число больше 65535) - нет не было.." Почему умножаешь? Еще раз извини за глупые вопросы, просто хочу разобратся в алгоритме, а не тупо сдать программу написанную не мной... |
Сообщ.
#27
,
|
|
|
1. Закрываться на кнопку Esc.
.DATA ........................ ExitMsg db 'Для завершения нажмите Esc', '$' .......................... .CODE .......................... @@Exit: lea dx, ExitMsg mov ah,09h int 21h ; ожидание нажатия клавиши Esc @@WaitForEsc: mov ah,07h ; ожидаем нажатие любой клавиши int 21h cmp al, 1Bh ; 1Bh - код клавиши Esc jnz @@WaitForEsc ; если это не Esc, то повторить ............................. 2. Откуда умножение. Show_ax - подпрограмма для вывода на экран. Именно в ней и происходит преобразование в десятичный или в восьмеричный вид. Поэтому она вызывается в теле основной программы (Main) два раза - один раз для десятичного отображения введенного числа, другой раз для восьмеричного отображения того же числа. Там и происходит деление исходного числа на основание системы счисления (основание системы передается в п/п в регистре cx). Вот вызов для восьмеричной: mov ax, Numer mov cx, 8 call Show_ax Обрати внимание на закомментированную строку в начале Show_ax (mov cx, 10). Эта процедура изначально предназначалась лишь для десятичного отображения, но теперь в регистре cx можно передавать любое значение для системы счисления не превосходящее 10 (если нужно больше 10 - тогда нужно усложнять процедуру). Как ты справедливо отмечаешь, исходное число (ax) нужно делить на основание системы - так и происходит (div cx). Оператор div cx - содержимое регистровой пары dx:ax делится на cx (поэтому перед делением обнуляется dx - xor dx,dx), частное от деления помещается в ax, а остаток в dx. Т.к. делим мы на небольшие числа (в пределах 10), то dh=0, а в dl - нужный нам остаток. Чтобы не повторяться дам ссылку, где кратко объясняется работа процедуры Show_ax, только в пояснении замени число 10 на "основание системы счисления" Сложение чисел . Str2Num - это процедура преобразования строки в число - поэтому там и нет деления, зато есть умножение. Давай посмотрим что делает программа (с метки Main): 1. Вводится строка, содержащая символы ('-', '0',... ,'9') - это еще не число. 2. Вызывается процедура преобразования строки в число Str2Num. Она из строки получает двухбайтное число Numer. 3. Число Numer выводится в десятичной системе - процедура Show_ax. 4. Число Numer выводится в восьмеричной системе - процедура Show_ax. 5. Ожидается нажатие Esc. Если не критично (в смысле условия задания), то чтобы не путаться, можешь удалить всю процедуру Str2Num и её вызовы из программы. Само число набери в строке (Numer dw -123). Вызывая два раза Show_ax увидишь как десятичное, так и восьмеричное представление числа Numer. Прикреплённый файлINPUT_5.ZIP (1.07 Кбайт, скачиваний: 140) |
Сообщ.
#28
,
|
|
|
Я к твоему файу Input_2.asm добавила вот такое:
@@Exit: ; ожидание нажатия любой клавиши mov ah,01h int 21h cmp al, 1Bh ; 1Bh - код клавиши Esc jnz @@Exit ; если это не Esc, то повторить mov ax,4c00h int 21h Main ENDP Теперь прога закрывается после нажатия кнопки ESC, а если я хочу ввести несколько чисел, вот например ввела первое число, программа его перева и напечатала результат, а потом чтоб опять вывелось приглашение 'Введите число (-32768..+32767): , как такое сделать? P.S с умножением разобралась, спасибо !!! |
Сообщ.
#29
,
|
|
|
Зацикли. Если не Esc, то переход не на метку @@WaitForEsc, a к приглашению ввести число - к новой метке @@Input.
Main PROC FAR mov ax, @DATA mov ds, ax mov es, ax @@Input: ; ввод числа с клавиатуры (строки) lea dx, Prompt mov ah,09h int 21h Прикреплённый файлINPUT_6.ZIP (1.85 Кбайт, скачиваний: 134) |
Сообщ.
#30
,
|
|
|
Ясненько
Павел, вопрос немного не по теме, может знаешь где можна проконсультироватся по UML (унифицированный язык моделирования)? Я спрашивала на нескольких форумах, но именно в разделе UML людей совсем нет, и мой вопрос остался без ответа. |
Сообщ.
#31
,
|
|
|
Нет, про UML ничего не знаю. Попробуй погуглить, пояндексить или порамблерить. Ещё существует "студенческий коллективный разум" внутри собственной группы или потока .
|
Сообщ.
#32
,
|
|
|
Я обучаюсь заочно, так что студенческий коллективный разум внутри собственной группы или потока - это исключено
|
Сообщ.
#33
,
|
|
|
Привет, Павел! У меня возникли сложности при написании лабораторной работы. У меня задание: найти произведение элементов массива, и максимальное значение.
Работаю я в TASM, а в учебнике нашла похожие примеры, но для MASM. Вобщем кое-как слепила из-этих примеров себе лабораторную. Но при компилировании возникали ошибки, так как Tasm не понимал команды Masm. Пыталась изменять команды, чтоб исходник компилировался в TASM, но все время возникают ошибки. Павел, помоги мне подправить этот исходник. Очень тебе прошу ! ; Подготовка программы: ; MASM /Z /ZI /N P, P, P; ; LINK /CO P,P; ; Програмные мтроки text segment 'code' assume cs:text, ds:data ; Определения count = 80; KEYBOARD STRUCT maxInput BYTE count ; Максималтный размер буфера inputCount BYTE ? ; Количество введеных символов buffer BYTE count DUP(?) ; Введенные символы KEYBOARD ENDS myproc proc mov AX,data mov DS,AX ; Очистка экрана mov ax,0003h int 10h ; Читает строку символов из стандартного устройства ввода mov ah,0Ah mov dx,OFFSET kybdData int 21h ; Перемещение курсора в начало следующец строки mov ah,02h mov dl,0Ah int 21h mov bl,kybdData.inputCount mov dx,OFFSET kybdData add dx,2 add dx,bx mov di,dx mov byte ptr [di],'$' ; Выводит строку, оканчивающуюся символом "$", на стандартное устройство вывода mov ah,09h mov dx,OFFSET kybdData add dx,2 int 21h ; Добуток елеиентів масиву mov si,OFFSET arrayB mov cx,(LENGTHOF arrayB)-1 mov ax,[si] L1: add si,2 ; Поскольку массив arrayB типа WORD mov bx,[si] mul bx ; В ax будет гаходится результат умножения loop L1 ; максимальне значення масиву mov si,OFFSET arrayB mov cx,(LENGTHOF arrayB)-1 mov ax,[si] .WHILE cx > 0 add si,2 ; Поскольку массив arrayB типа WORD dec cx .IF ax < [si] mov ax,[si] ; .ELSE ; mov bx,ax .ENDIF .ENDW ; Завершим программу mov AX,4C00h int 21h myproc endp text ends ; Поля данных data segment kybdData KEYBOARD <> arrayB WORD 2, 1, 1, 1, 1, 1, 3, 1, 1, 5, 1 data ends stack segment para stack 'stak' db 128 dup (?) stack ends end myproc |
Сообщ.
#34
,
|
|
|
Привет, Deffi
Вообще-то, это уже вопрос для отдельной темы. Поэтому отвечу в приват. |