На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Запрещается обсуждать написание вирусов, троянов и других вредоносных программ!
2. Помните, что у нас есть FAQ раздела Assembler и Полезные ссылки. Посмотрите, возможно, там уже имеется решение вашего вопроса.

3. Настоятельно рекомендуем обратить особое внимание на правила форума, которые нарушаются чаще всего:
  3.1. Заголовок темы должен кратко отражать её суть. Темы с заголовками типа "Срочно помогите!" или "Ассемблер" будут отправляться в Корзину для мусора.
  3.2. Исходники программ обязательно выделяйте тегами [code]...[/code] (одиночные инструкции можно не выделять).
  3.3. Нежелательно поднимать старые темы (не обновлявшиеся более года) без веской на то причины.

Не забывайте также про главные Правила форума!

Добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: Jin X, Qraizer
Страницы: (3) 1 [2] 3  все  ( Перейти к последнему сообщению )  
> Перевод целых чисел из десятичной в восьмиричную систему счисления , Перевод целых чисел из десятичной в восьмиричную систему счисления
      Кстати, а как переводятся отрицательные числа ?
        Для вывода отрицательных чисел нужно добавить строки в процедуру Show_ax, проверяющие знак числа. В случае отрицательного числа нужно вывести знак минус "-", и преобразовать число в регистре ax.

        ExpandedWrap disabled
                  ; если число в ax отрицательное, то
                  ;1) напечатать '-'
                  ;2) сделать ax положительным
                  or      ax, ax
                  jns     @@Conv
                  push    ax
                  mov     dx, '-'
                  mov     ah, 2           ; ah - функция вывода символа на экран
                  int     21h
                  pop     ax
           
                  neg     ax


        В итоге это будет выглядеть

        ExpandedWrap disabled
          ; выводит число в регистре 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).
          Немного помудрил...
          Нужно увеличить буфер ввода на один символ ("-32768" длиной 6 символов)

          ExpandedWrap disabled
            KeyBuf  db      7, 0, 7 dup(0)      ;max,len,string,CR(0dh)


          Str2Num получилась такая

          ExpandedWrap disabled
            ; преобразования строки в число
            ; на входе:
            ; 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) перед циклом преобразования
          ExpandedWrap disabled
                    ;если в строке первый символ '-'
                    ; - перейти к следующему
                    ; - уменьшить количество рассматриваемых символов
                    cmp     byte ptr [si], '-'
                    jne     @@Loop
                    inc     si
                    dec     cx

          2) после цикла преобразования
          ExpandedWrap disabled
                    pop     si         ;проверка на знак
                    push    si
                    inc     si
                    cmp     byte ptr [si], '-'
                    jne     @@StoreRes
                    neg     ax
            @@StoreRes:

          3) внутри цикла преобразования
          ExpandedWrap disabled
                    js      @@Error    ; Если результат стал отрицательным

          4) Чтобы была возможность просмотреть первый символ, нужно в начале процедуры сохранить si, а в конце процедуры извлечь из стека (в обоих случаях завершения - правильном и ошибочном).


          Т.е. идея следующая.
          1) Если в строке символ "-", то его поначалу пропускаем и получаем положительный результат.
          2) Потом опять проверяем исходную строку на наличие "-". Если он есть, то делаем результат отрицательным (neg ax).
          3) Таким образом, во время выполнения преобразования временный результат все время должен быть положительным (флаг знака S - сброшен) - это и есть проверка внутри цикла.
            Сейчас еще раз потестировал - нашел ошибку. Не вводиться число -32768.
            Нужно заменить строку
            ExpandedWrap disabled
                      js      @@Error    ; Если результат стал отрицательным

            на строки
            ExpandedWrap disabled
                      cmp     ax, 8000h
                      ja      @@Error

            И еще добавить проверку для случая 32768. В целом Str2Num
            ExpandedWrap disabled
              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 Кбайт, скачиваний: 150)
              Павел, тогда получается что 100 (Dec) = 144 (Oct) и -100 (Dec) = -144 (Oct) хотя если проверить на инженерном калькуляторе в Excel -100 (Dec) = 7777777634 (Oct) Так вот :(
              Прикреплённый файлПрикреплённый файлСкриншот.png (7.23 Кбайт, скачиваний: 290)
                Deffi
                Думаю, что программа считает правильно. Ведь она не не изменяет само значение числа (переменную Number). А только в двух форматах (десятичном и восьмеричном) выводит на экран. И если это число -1448 сложить с числом 1448 должен получиться 0. А "калькулятор" производит преобразование из десятичной в восьмеричную без учета знака.
                Можешь даже проверить (если не лень). Измени программу - чтобы Str2Num была новая, а Show_ax - старая-беззнаковая. И увидишь такой же результат.
                  Немного не поняла твоего пояснения, извини.

                  Добавлено
                  Программа просто добавляет знак минуса на экран и все, и считает как положительные.
                    Нет, 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)
                      Ты так подробно все объясняешь, что и wikipedia нет надобности читать.
                      У нас даже преподаватели так подробно не объясняют.
                        Павел, чесно сказать уже и совесть не позволяет что-либо у тебя еще спрашивать, но может напишешь как сделать, чтоб после ввода пользователем числа экзешник не закрывался автоматически, а только когда я нажму 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) - нет не было.."

                        Почему умножаешь?

                        Еще раз извини за глупые вопросы, просто хочу разобратся в алгоритме, а не тупо сдать программу написанную не мной...
                          1. Закрываться на кнопку Esc.
                          ExpandedWrap disabled
                            .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). Вот вызов для восьмеричной:
                          ExpandedWrap disabled
                                    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 Кбайт, скачиваний: 139)
                            Я к твоему файу Input_2.asm добавила вот такое:
                            ExpandedWrap disabled
                              @@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 с умножением разобралась, спасибо !!!
                              Зацикли. Если не Esc, то переход не на метку @@WaitForEsc, a к приглашению ввести число - к новой метке @@Input.
                              ExpandedWrap disabled
                                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 Кбайт, скачиваний: 133)
                                Ясненько :)
                                Павел, вопрос немного не по теме, может знаешь где можна проконсультироватся по UML (унифицированный язык моделирования)? Я спрашивала на нескольких форумах, но именно в разделе UML людей совсем нет, и мой вопрос остался без ответа.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) 1 [2] 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0891 ]   [ 14 queries used ]   [ Generated: 23.05.24, 05:58 GMT ]