Содержание
Как известно, в римской системе счисления для обозначения цифр используются комбинации букв латинского алфавита — I, II, III, IV и т.д. В этой статье рассмотрим один из вариантов алгоритма перевода числа из арабской системы в римскую и обратно.
Римская система счисления и большие числа
В современном стиле для обозначения римских цифр могут использоваться следующие латинские символы:
I | V | X | L | C | D | M |
1 | 5 | 10 | 50 | 100 | 500 | 1000 |
Хотя, в таблице символов Unicode имеются символы для обозначения римских цифр большего порядка. Например, символ U+2188, обозначающий цифру 100 000. Но, так как мы будем работать в консоли, а в ней менять шрифт — дело довольно проблематичное, то сразу оговоримся, что наш алгоритм будет использовать только эти семь символов. При необходимости, Вы сможете самостоятельно доработать алгоритм для вывода чисел большего порядка, например 1000 000 и более.
M D C X C V
1000 + 500 + 100+10+100+5
Как записывается число в римской системе счисления
Например, возьмем число 1123 (одна тысяча сто двадцать три). Разберем это число на слагаемые, соответствующие символам в римской системе:
1123 = 1000 + 100 + 10 + 10 + 1 + 1 + 1
В итоге, получим следующую римскую цифру:
1000 | 100 | 10 | 10 | 1 | 1 | 1 |
M | C | X | X | I | I | I |
то есть: 1123 = MCXXIII
Соответственно, если число будет равно 2123, то, используя ту же самую схему, получим MMCXXII. Первый вариант алгоритма, который приходит на ум, может быть такой:
- Раскладываем число на слагаемые из таблицы соответствия латинских символов и цифр, то есть любое число должно в итоге получаться только из суммы строго заданных слагаемых
- Проходим по списку слагаемых по порядку и составляем из символов строку, соответствующую заданному числу.
Но, не всё так просто, как кажется. Например, как записать число 90? Следуя правилу выше мы могли бы сказать, что так:
90 = 50 + 10 + 10 + 10 + 10 = LXXXX
а нет, число 90 выглядит вот так: XC
, то есть читается как «на 10 меньше, чем 100«. По этому же правилу записываются римские числа: 4 (IV), 9 (IX), 40 (XL), и 900 (CM). Соответственно, наша таблица соответствий арабских и римских чисел становится вот такой:
I | V | IX | X | L | XC | C | CD | D | CM | M |
---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 9 | 10 | 50 | 90 | 100 | 400 | 500 | 900 | 1000 |
Перевод числа из арабской системы в римскую
При таких исходных данных, как в таблице, разложение числа на слагаемые уже не будет таким уж эффективным решением — надо будет каждый раз проверять условие того, что очередное слагаемое не относится к числами типа «на 10 меньше чем…» или «на 100 меньше, чем…» и т.д. Поэтому, итоговое решение задачи по переводу числа из арабской системы в римскую можно представить следующим образом:
public static string ToRoman(int number) { //таблица соответствия арабских и римских цифр (int number, string symbol)[] table = new (int num, string symbol)[13] { (1,"I"), (4,"IV"), (5,"V"), (9,"IV"), (10,"X"), (40,"XL"), (50,"L"), (90,"XC"), (100,"C"), (400,"CD"), (500,"D"), (900,"CM"), (1000,"M") }; string result = ""; int N = number; int i = 12; while (N > 0) { //ищем число в таблице меньше или равное числу N //просматриваем массив, начиная с последнего элемента while (table[i].number > N) { i--; } //добавляем к результату очередную римскую цифру result += table[i].symbol; //отнимаем от числа, которое переводим, значение из таблицы N -= table[i].number; } return result; }
Проверим работу нашего метода:
Console.WriteLine(ToRoman(95)); Console.WriteLine(ToRoman(465)); Console.WriteLine(ToRoman(923)); Console.WriteLine(ToRoman(1223));
CDLXV
CMXXIII
MCCXXIII
Перевод числа из римской системы в арабскую
Обратные перевод числа из римской системы счисления в арабскую заключается в том, что строка, представляющая собой римское число также должны анализироваться с наибольшего разряда (у нас это тысячи). В этом случае, метод перевода числа может выглядеть следующим образом:
public static int ToArabic(string romanNumber) { (int number, string symbol)[] table = new (int num, string symbol)[13] { (1,"I"), (4,"IV"), (5,"V"), (9,"IV"), (10,"X"), (40,"XL"), (50,"L"), (90,"XC"), (100,"C"), (400,"CD"), (500,"D"), (900,"CM"), (1000,"M") }; int i = 12; int p = 1; int res = 0; while (p <= romanNumber.Length) { while (romanNumber.Substring(p - 1, table[i].symbol.Length) != table[i].symbol) { i--; if (i == 0) break; } res += table[i].number; p += table[i].symbol.Length; } return res; }
Проверим работу метода ToArabic
совместно с предыдущим, то есть переведем число вначале в римскую систему, а затем — обратно в арабскую. Если результаты совпадут, то можно считать, что наш алгоритм работает верно.
int number = 1923; string roman = ToRoman(number); int arabic = ToArabic(roman); Console.WriteLine($"{number} -> {roman} -> {arabic}");
Результат:
Как видно, результаты перевода совпали.
Итого
Перевод числа из арабской системы счисления в римскую и обратно должен учитывать не только основные символы из которых складываются римские цифры, но и, если так можно выразится, промежуточные числа типа IX, XC, CD и прочие. Представленные выше методы перевода чисел из арабской системы в римскую и обратно будут корректно работать для чисел не более 2999, так как после этого числа в римской системе счисления появляются новые символы, обозначающие как 1000 (и там символ не M),так и другие числа типа 5000, 100000 и т.д. При желании, методы можно дописать для работы и с этими большими числами.