Blog. Just Blog

Запись числа римскими цифрами на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Запись числа римскими цифрами на Ассемблере
Запись числа римскими цифрами на Ассемблере

Задачки на запись натурального числа римскими цифрами очень часто встречаются на различных олимпиадах по программированию. Я решил нарисовать свой вариант решения задачи на Ассемблере.

Натуральные числа записываются при помощи повторения этих цифр. При этом применяется следующее базовое правило: одна и та же букво-цифра не может повторяться в записи числа более 3-х раз подряд. Для этого введены дополнительные двухбуквенные комбинации и, если меньшая букво-цифра стоит перед большей, то меньшая вычитается из большей. В табличке это наглядно видно. Но ограниченный набор букво-цифр приводит к тому, что максимальное число, которое можно записать базовым набором римских цифр, не может превышать десятичного числа 3999 (MMMCMXCIX). Также в римской записи нет нулевого значения, отрицательных и дробных чисел.

С переводом числа в римскую запись все достаточно просто. Похожий алгоритм используется, например, для записи числа словами. Проверив граничные значения, поочередно проверяем значение числа значению буквенного числа, если больше - вычитаем и дописываем соответствующее ему строковое значение в итоговое значение. И так до достижения нулевого остатка.
  1. ;---------------------------------------------
  2. ; Запись числа римскими цифрами
  3. ;---------------------------------------------
  4. ; dDec - число в интервале 1..3999
  5. ; lpBuff - указатель на буфер-приемник строки
  6. ;---------------------------------------------
  7. proc dec2roman dDec:DWORD, lpBuff:DWORD
  8.         pusha
  9.  
  10.         mov     eax,[lpBuff]
  11.         mov     byte [eax],0
  12.         mov     ebx,[dDec]
  13.  
  14.         ; Проверить граничные значения
  15.         cmp     ebx,3999
  16.         ja      .loc_ret
  17.         cmp     ebx,1
  18.         jb      .loc_ret
  19.  
  20. .loc_loop:
  21.         or      ebx,ebx
  22.         jz      .loc_ret
  23.  
  24.         mov     esi,.rtable
  25. @@:
  26.         lodsd
  27.         mov     edx,eax
  28.         lodsd
  29.         cmp     ebx,edx
  30.         jb      @b
  31.         sub     ebx,edx
  32.         invoke  lstrcat,[lpBuff],eax
  33.         jmp     .loc_loop
  34. .loc_ret:
  35.         popa
  36.         ret
  37.  
  38. .rtable dd 1000,.sz1000
  39.         dd 900,.sz900
  40.         dd 500,.sz500
  41.         dd 400,.sz400
  42.         dd 100,.sz100
  43.         dd 90,.sz90
  44.         dd 50,.sz50
  45.         dd 40,.sz40
  46.         dd 10,.sz10
  47.         dd 9,.sz9
  48.         dd 5,.sz5
  49.         dd 4,.sz4
  50.         dd 1,.sz1
  51.         dd 0
  52.  
  53. .sz1000 db 'M',0
  54. .sz900  db 'CM',0
  55. .sz500  db 'D',0
  56. .sz400  db 'CD',0
  57. .sz100  db 'C',0
  58. .sz90   db 'XC',0
  59. .sz50   db 'L',0
  60. .sz40   db 'XL',0
  61. .sz10   db 'X',0
  62. .sz9    db 'IX',0
  63. .sz5    db 'V',0
  64. .sz4    db 'IV',0
  65. .sz1    db 'I',0
  66.  
  67. endp
Процесс обратной конвертации сложнее. Дело в том, что за столетия существования римских цифр появились несколько вариантов записи чисел. Это всякие упрощенные варианты. Лично я считаю, что если есть алгоритм конвертации в одну сторону со своими правилами, то обратный алгоритм должен в точности выполнять эти же правила. Соответственно, любые другие записи римских чисел будут считаться ошибочными, даже если формально их можно обосновать и конвертировать.
  1. ;-----------------------------------------------------
  2. ; Конвертация числа из римской записи
  3. ;-----------------------------------------------------
  4. ; На входе:
  5. ;   lpBuff - указатель на строку с римским числом
  6. ; На выходе:
  7. ;   EAX = число
  8. ;-----------------------------------------------------
  9. proc roman2dec lpBuff:DWORD
  10.         pusha
  11.  
  12.         xor     ebx,ebx
  13.         mov     esi,[lpBuff]
  14.  
  15.         ; Строка пустая
  16.         cmp     byte [esi],0
  17.         jz      .loc_ret
  18.  
  19.         ; Тысячи
  20.         mov     ecx,3
  21. .loc_t:
  22.         cmp     byte[esi],'M'
  23.         jne     .loc_h
  24.         inc     esi
  25.         add     ebx,1000
  26.         loop    .loc_t
  27.  
  28.         ; Сотни
  29. .loc_h:
  30.         cmp     word[esi],'CM'
  31.         jne     @f
  32.         add     ebx,900
  33.         lodsw
  34.         jmp     .loc_d
  35. @@:
  36.         cmp     byte[esi],'D'
  37.         jne     @f
  38.         add     ebx,500
  39.         inc     esi
  40.         jmp     .loc_c
  41. @@:
  42.         cmp     word[esi],'CD'
  43.         jne     .loc_c
  44.         add     ebx,400
  45.         lodsw
  46.         jmp     .loc_d
  47. .loc_c:
  48.         mov     ecx,3
  49. @@:
  50.         cmp     byte[esi],'C'
  51.         jne     .loc_d
  52.         inc     esi
  53.         add     ebx,100
  54.         loop    @b
  55.  
  56.         ; Десятки
  57. .loc_d:
  58.         cmp     word[esi],'XC'
  59.         jne     @f
  60.         add     ebx,90
  61.         lodsw
  62.         jmp     .loc_o
  63. @@:
  64.         cmp     byte[esi],'L'
  65.         jne     @f
  66.         add     ebx,50
  67.         inc     esi
  68.         jmp     .loc_x
  69. @@:
  70.         cmp     word[esi],'XL'
  71.         jne     .loc_x
  72.         add     ebx,40
  73.         lodsw
  74.         jmp     .loc_o
  75. .loc_x:
  76.         mov     ecx,3
  77. @@:
  78.         cmp     byte[esi],'X'
  79.         jne     .loc_o
  80.         inc     esi
  81.         add     ebx,10
  82.         loop    @b
  83.  
  84.         ; Единицы
  85. .loc_o:
  86.         cmp     word[esi],'IX'
  87.         jne     @f
  88.         add     ebx,9
  89.         lodsw
  90.         jmp     .loc_done
  91. @@:
  92.         cmp     byte[esi],'V'
  93.         jne     @f
  94.         add     ebx,5
  95.         inc     esi
  96.         jmp     .loc_i
  97. @@:
  98.         cmp     word[esi],'IV'
  99.         jne     .loc_i
  100.         add     ebx,4
  101.         lodsw
  102.         jmp     .loc_done
  103. .loc_i:
  104.         mov     ecx,3
  105. @@:
  106.         cmp     byte[esi],'I'
  107.         jne     .loc_done
  108.         inc     esi
  109.         inc     ebx
  110.         loop    @b
  111.  
  112. .loc_done:
  113.         ; Остались необработанные символы?
  114.         lodsb
  115.         or      al,al
  116.         jz      .loc_ret
  117.  
  118.         ; Да, число записано неправильно
  119.         xor     ebx,ebx
  120. .loc_ret:
  121.         mov     [esp+28],ebx
  122.         popa
  123.         ret
  124. endp
В приложении примеры программ с исходными текстами, которые преобразуют десятичное число в римскую запись и обратно.

Примеры программ с исходными текстами (FASM)Примеры программ с исходными текстами (FASM)

Roman.Decimal.Demo.zip (5,431 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 662 | Комментариев: 0

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0083 сек.) / Память: 4.5 Mb
Наверх