Алгоритм перевода чисел из арабской системы в римскую и обратно

Как известно, в римской системе счисления для обозначения цифр используются комбинации букв латинского алфавита — 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. Первый вариант алгоритма, который приходит на ум, может быть такой:

  1. Раскладываем число на слагаемые из таблицы соответствия латинских символов и цифр, то есть любое число должно в итоге получаться только из суммы строго заданных слагаемых
  2. Проходим по списку слагаемых по порядку и составляем из символов строку, соответствующую заданному числу.

Но, не всё так просто, как кажется. Например, как записать число 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));
XCV
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}");

Результат:

1923 -> MCMXXIII -> 1923

Как видно, результаты перевода совпали.

Итого

Перевод числа из арабской системы счисления в римскую и обратно должен учитывать не только основные символы из которых складываются римские цифры, но и, если так можно выразится, промежуточные числа типа IX, XC, CD и прочие. Представленные выше методы перевода чисел из арабской системы в римскую и обратно будут корректно работать для чисел не более 2999, так как после этого числа в римской системе счисления появляются новые символы, обозначающие как 1000 (и там символ не M),так и другие числа типа 5000, 100000 и т.д. При желании, методы можно дописать для работы и с этими большими числами.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии