Код магнитолы

JS - телефон

Оппозиция в России ?

Россия и Украина

Мысли в слух...

JS - часы

Российская...власть ?

Skype

Создаём сайт

Любимые сериалы

Гостевая


На главную

Преобразуем ASCII-символы в двоичный код...и - обратно:

На процессе преобразования (прямого и обратного) остановимся поподробнее, поскольку - это самая интересная часть проекта. Начнём с того, что внимательно рассмотрим весь процесс.
Набранное число состоит из символов. Когда мы нажимаем на кнопку арифмометра комп, при помощи API-функции (см. процедуру nabor), добавляет символ на дисплей. Кроме того, этот символ (символы) остаются в переменной buf db 10 dup (0). В этой переменной мы задаём размер буфера и, попутно, очищаем его (заполняем нoлями).
На каждую цифру-символ, от 0 до 9, уходит 1 байт, а на hex-представление - 1 тетрада. Т.е., в hex-варианте в байт помещается 2 символа и первый - это 3 (см. таблицу ASCII-кодов), а второй, в нашем случае, это цифра 0-9.
И так, набор ASCII-символов в переменной buf. Именно из этого источника мы будем брать символы, по-байтно, для преобразования их в двоичный код. Для перевода ASCII-символа (hex-символа) в двоичный код мы удалим из него 3.
К примеру, мы набрали число 1234. В переменной buf оно сохранилось в виде:
          1234 --> 31323334h
Теперь мы должны умножить соответствующий символ на степень основания и сложить получившиеся результаты. Но...степень основания мы не узнаем, пока не прочтём все цифры и по их количеству не определим порядок числа. М-да... Оказывается - выход есть:
          ((((0)*10+1)*10 + 2)*10 + 3)*10 + 4 = 1234 
Спасибо товарищу Горнеру за оригинальное решение.
Код процедуры:

  asc2bin proc                        
    pushad
    xor  ebx,ebx          ;обнулимся...
    xor  eax,eax          ;EAX=0, накопитель дв.кода             
    mov  edi,ten          ;10 - основание системы счисления
    lea  ecx,buf          ;адрес 1-го ASCII-символа
    b_cycl:
      mov  bl,[ecx]       ;добавим в EBX ASCII-символ
      or   bl,bl          ;закончились символы?
      jz   fin            ;завершаем преобразование
      and  bl,0Fh         ;преобразуем ASCII-символ
      mul  edi            ;EDX:EAX = EAX*10
      add  eax,ebx        ;промежуточная сумма
      jc   exit           ;если CF=1
      inc  ecx            ;к следующему символу
      jmp  b_cycl         ;повторим
      fin:
        mov  bin,eax      ;сохраним дв.код
        popad
      exit:               ;для возможной обработки CF
        ret
  asc2bin endp
                         
                        рис.8

Теперь в переменной "bin" у нас содержимое "buf" в двоичном виде.
Обратное преобразование: полученный, в результате арифметической операции, двоичный код мы будем делить на основание системы счисления, а остатки от деления преобразовывать в ASCII-символы, путём прибавления к ним 3 и, опять - по-байтно.
Код процедуры:
   
  bin2asc  proc
    pushad                  
    mov  eax,dword ptr res
    lea  edi,buf
    mov  ebx,ten              ;10 - основание системы счисления
    xor  ecx,ecx              ;обнуляем счётчик
    conv:                    
      xor  edx,edx            ;обнулимся...
      div  ebx                ;EAX=частное, EDX=остаток
      add  dl,"0"             ;cформируем ASCII-символ ("0"->30h)
      push edx                ;сохраним для разворота
      inc  ecx                ;ECX+1 --> для "rev"
      test eax,eax            ;преобразование закончено?
      jnz  conv               ;если нет - продолжаем
    rev:                      ;разворачиваем символы
      pop  edx                ;символ из стека в DL
      mov  [edi],dl           ;занесём ASCII-символ в буфер
      inc  edi                ;смещаемся
      loop rev                ;повторяем, пока ЕСХ не 0
      mov  byte ptr [edi],0   ;добавляем 0 в конец строки  
    exit:
      popad 
      ret
  bin2asc endp
  
                        рис.9
						
Что-бы перейти к операциям с дробными (вещественными) числами, т.е. добавить на арифмометр кнопку с символом ".", необходимо продолжить преобразование в направлении ASCII- символ --> вещественное число и подключить к арифметике сопроцессор.

Непростая...арифметика

Она - действительно непростая. Наш арифмометр работает с 4-мя основными арифметическими действиями, но расчитан на переменные типа "dword" и "qword". А такие числа напрямую складывать и умножать - нельзя. Мы будем иметь дело с длинными числами.
Посмотрим, что это такое на примере операции сложения:
plus --> plu proc --> plu_ex --> pluex proc --> add_32 proc
Что-бы не запутатся в арифметике, разобьём её на вспомогательные процедуры (см. рис.9). Нас интересует последняя процедура:

  ;из файла data.inc:
  ;bin   dd  0,0 - 2-е число в дв.виде
  ;bin1  dd  0,0 - 1-е число в дв.виде
  ;res   dq  0,0,0,0 - итог операции (сложения) в дв.виде

  add_32 proc                   
    push eax                   ;сохраняем ЕАХ
    mov  eax,bin1               
    add  eax,bin               ;складываем младшие дв.слова 
    mov  dword ptr res,eax     
    mov  eax,bin1+4             
    adc  eax,bin+4             ;складываем старшие дв.слова, с учётом переноса               
    mov  dword ptr res+4,eax   
    pop  eax                   ;восстанавливаем ЕАХ
    ret
  add_32 endp

Команды ADC (сложение с учетом переноса) и SBB (вычитание с учетом займа) специально были введены для подобных операций. При сложении сначала складывают самые младшие (байты, слова) двойные слова командой ADD, а затем складывают все остальное командами ADC, двигаясь от младшего конца числа к старшему.
Например:

                   4357  -->   43     57
                 + 5128  --> + 51   + 28
                   ----        --     --
                   9485   =    94  +  85

Т.е. складываем младшие разряды, потом - старшие, а потом - "складываем" результаты. При этом учитываем, что вместо "85" могло получится, к примеру, "105".

P.S.

При пользовании арифмометром необходимо помнить:
-- арифмометр работает только с целыми, положительными числами
-- при делении арифмометр выдаёт только частное
-- код арифмометра не обрабатывает ошибки - программа просто зависнет...или отключится.
Удачи !

22.08.2018г.

...назад
дальше...