Запись числа римскими цифрами на Ассемблере
Запись числа римскими цифрами на Ассемблере
Задачки на запись натурального числа римскими цифрами очень часто встречаются на различных олимпиадах по программированию. Я решил нарисовать свой вариант решения задачи на Ассемблере.
Натуральные числа записываются при помощи повторения этих цифр. При этом применяется следующее базовое правило: одна и та же букво-цифра не может повторяться в записи числа более 3-х раз подряд. Для этого введены дополнительные двухбуквенные комбинации и, если меньшая букво-цифра стоит перед большей, то меньшая вычитается из большей. В табличке это наглядно видно. Но ограниченный набор букво-цифр приводит к тому, что максимальное число, которое можно записать базовым набором римских цифр, не может превышать десятичного числа 3999 (MMMCMXCIX). Также в римской записи нет нулевого значения, отрицательных и дробных чисел.
С переводом числа в римскую запись все достаточно просто. Похожий алгоритм используется, например, для записи числа словами. Проверив граничные значения, поочередно проверяем значение числа значению буквенного числа, если больше - вычитаем и дописываем соответствующее ему строковое значение в итоговое значение. И так до достижения нулевого остатка.
Code (Assembler) : Убрать нумерацию
- ;---------------------------------------------
- ; Запись числа римскими цифрами
- ;---------------------------------------------
- ; dDec - число в интервале 1..3999
- ; lpBuff - указатель на буфер-приемник строки
- ;---------------------------------------------
- proc dec2roman dDec:DWORD, lpBuff:DWORD
- pusha
- mov eax,[lpBuff]
- mov byte [eax],0
- mov ebx,[dDec]
- ; Проверить граничные значения
- cmp ebx,3999
- ja .loc_ret
- cmp ebx,1
- jb .loc_ret
- .loc_loop:
- or ebx,ebx
- jz .loc_ret
- mov esi,.rtable
- @@:
- lodsd
- mov edx,eax
- lodsd
- cmp ebx,edx
- jb @b
- sub ebx,edx
- invoke lstrcat,[lpBuff],eax
- jmp .loc_loop
- .loc_ret:
- popa
- ret
- .rtable dd 1000,.sz1000
- dd 900,.sz900
- dd 500,.sz500
- dd 400,.sz400
- dd 100,.sz100
- dd 90,.sz90
- dd 50,.sz50
- dd 40,.sz40
- dd 10,.sz10
- dd 9,.sz9
- dd 5,.sz5
- dd 4,.sz4
- dd 1,.sz1
- dd 0
- .sz1000 db 'M',0
- .sz900 db 'CM',0
- .sz500 db 'D',0
- .sz400 db 'CD',0
- .sz100 db 'C',0
- .sz90 db 'XC',0
- .sz50 db 'L',0
- .sz40 db 'XL',0
- .sz10 db 'X',0
- .sz9 db 'IX',0
- .sz5 db 'V',0
- .sz4 db 'IV',0
- .sz1 db 'I',0
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Конвертация числа из римской записи
- ;-----------------------------------------------------
- ; На входе:
- ; lpBuff - указатель на строку с римским числом
- ; На выходе:
- ; EAX = число
- ;-----------------------------------------------------
- proc roman2dec lpBuff:DWORD
- pusha
- xor ebx,ebx
- mov esi,[lpBuff]
- ; Строка пустая
- cmp byte [esi],0
- jz .loc_ret
- ; Тысячи
- mov ecx,3
- .loc_t:
- cmp byte[esi],'M'
- jne .loc_h
- inc esi
- add ebx,1000
- loop .loc_t
- ; Сотни
- .loc_h:
- cmp word[esi],'CM'
- jne @f
- add ebx,900
- lodsw
- jmp .loc_d
- @@:
- cmp byte[esi],'D'
- jne @f
- add ebx,500
- inc esi
- jmp .loc_c
- @@:
- cmp word[esi],'CD'
- jne .loc_c
- add ebx,400
- lodsw
- jmp .loc_d
- .loc_c:
- mov ecx,3
- @@:
- cmp byte[esi],'C'
- jne .loc_d
- inc esi
- add ebx,100
- loop @b
- ; Десятки
- .loc_d:
- cmp word[esi],'XC'
- jne @f
- add ebx,90
- lodsw
- jmp .loc_o
- @@:
- cmp byte[esi],'L'
- jne @f
- add ebx,50
- inc esi
- jmp .loc_x
- @@:
- cmp word[esi],'XL'
- jne .loc_x
- add ebx,40
- lodsw
- jmp .loc_o
- .loc_x:
- mov ecx,3
- @@:
- cmp byte[esi],'X'
- jne .loc_o
- inc esi
- add ebx,10
- loop @b
- ; Единицы
- .loc_o:
- cmp word[esi],'IX'
- jne @f
- add ebx,9
- lodsw
- jmp .loc_done
- @@:
- cmp byte[esi],'V'
- jne @f
- add ebx,5
- inc esi
- jmp .loc_i
- @@:
- cmp word[esi],'IV'
- jne .loc_i
- add ebx,4
- lodsw
- jmp .loc_done
- .loc_i:
- mov ecx,3
- @@:
- cmp byte[esi],'I'
- jne .loc_done
- inc esi
- inc ebx
- loop @b
- .loc_done:
- ; Остались необработанные символы?
- lodsb
- or al,al
- jz .loc_ret
- ; Да, число записано неправильно
- xor ebx,ebx
- .loc_ret:
- mov [esp+28],ebx
- popa
- ret
- endp
Просмотров: 866 | Комментариев: 0
Метки: Assembler, полезные функции
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Комментариeв нет
Добавить комментарий
Заполните форму для добавления комментария