Pull to refresh

Из Басры в Рим. Преобразовываем арабские числа в римские

Reading time 3 min
Views 23K
Доброе время суток, Хабраюзер.

Разрабатывая в основном для платформы J2ME, я всегда старался вносить какие то изюминки в свои проекты. Так, однажды, мне понадобилось выделить пункты меню.

Стандартное решение, через тире или пронумеровав их, использовать не очень хотелось, но другие варианты тогда у меня отсутствовали. Обдумывая как бы лучше оформить эти пункты, я случайно наткнулся на свою старую школьную тетрадку по истории, в которой пункты были пронумерованы с использованием римских цифр. Бинго!

Стоит признаться, на то время моих познаний в римских цифрах хватало только для подсчета до второго-третьего десятка. Что вообще то для нумерации пунктов должно было хватить. Но как любой программист, захотелось иметь готовое решение, которое смогло бы переводить любые целые десятичные арабские числа в эквивалентные им римские.

В Википедии нашлась статья с описанием Римской СС, и вскоре я набросал алгоритм перевода из арабских чисел в римские.

Основные числа:

I — 1
V — 5
X — 10
L — 50
C — 100
D — 500
M — 1000

Ноль отсутствует вообще, поэтому будем использовать пустое значение.

Итак, сам алгоритм достаточно прост:

1. Выделяем (если есть) количество целых тысяч. Полученное значение позволить сгенерировать строку с n количеством «M» (читаем, n*1000).
Пример: 2012 после первого пункта даст «MM»

2. Получаем остаток после деления на 1000, чтобы выделить в дальнейшем следующие значения.

3. Выделяем (если возможно), целые 500. При этом учитываем что если полученное значение равно 4 (5+4=9), то следует записывать как значение 1000-100, что в римский СС равнозначно «CM».
Пример: 1887 после этого пункта даст нам «MD».
1945 соответственно «MCM».

4. Получаем остаток от деления на 500.

5. Делим на 100 чтобы выделить целые сотни и складываем к предыдущему результату. Учитываем что если получили 4, что равнозначно 400, то записываем как 500-100, то есть «CD».
Пример: 1709 даст после этого шага «MDCCC».

6. Получаем остаток от деления на 100.

7. Выделяем из него целые пол сотни. Если значение будет равно 4 (то есть 90), то записываем как 100-10, что равно «XC». Иначе прибавляем к строке «L»
Пример: 1986 после всего выдаст нам «MCML».

8. Выделяем остаток от 50.

9. Выделяем целое количество десятков и складываем к строке n раз символ «X». При этом учитываем что 40 пишется как 50-10, то есть «XL».
Пример: 1986 после всего выдаст нам «MCMLXXX».

10. Получаем остаток от деления на 10. Этот шаг отличается от других тем, что можно сразу приравнять остаток к его эквиваленту. 1=I, 7=VII и так далее.

После перебора числа этим алгоритмом мы получаем примерно такое:
2012 == MMXII
Ниже исходник на Java, реализующий алгоритм.
public class RoManiac {

 /*
Основные числа:
I - 1
V - 5
X - 10
L - 50
C - 100
D - 500
M - 1000
Ноль отсутствует вообще,поэтому будем использовать пустое значение
*/
    // Основной метод преобразования из арабских в римские
  

   public static String convert(int in) {
        StringBuffer a = new StringBuffer("");
        // Выделяем тысячи
        int m1 = in / 1000;
        a.append(M(m1));
        // то что осталось после тысяч
        int m2 = in % 1000;

        // Выделяем пятьсот из остатка от тысячи
        int d1 = m2 / 500;
        a.append(D(d1));
        // остаток после выделения полтысячи
        int d2 = m2 % 500;

        // Выделяем сотни из остатка
        int c1 = d2 / 100;
        a.append(C(c1));
        // остаток из сотен
        int c2 = d2 % 100;

        // Выделяем полсотни
        int l1 = c2 / 50;
        a.append(L(l1));
        // остаток
        int l2 = c2 % 50;

        // Выделяем десятки
        int x1 = l2 / 10;
        a.append(X(x1));
        // остаток
        int x2 = l2 % 10;

        // Выделяем то что осталось
        a.append(basic(x2));
        return a.toString();
    }

    // преобразовываем целые тысячи
    // с значениями,кратными десяти, но не 5,всё просто
    private static String M(int in) {
        StringBuffer a = new StringBuffer("");
        int i = 0;
        while (i < in) {
            a.append("M");
            i++;
        }
        return a.toString();
    }
    // преобразовываем целые сотни
    private static String C(int in) {
        if (in == 4) return "CD"; //если 400, то 500-100
        else if ((in != 0) && (in < 4)) {
            StringBuffer a = new StringBuffer("");
            int i = 0;
            while (i < in) {
                a.append("C");
                i++;
            }
            return a.toString();
        }
        else return "";
    }

// целые десятки

    private static String X(int in) {
        if (in == 4) return "XL"; // если 40, то 50-10
        else if ((in != 0) && (in < 4)) {
            StringBuffer a = new StringBuffer("");
            int i = 0;
            while (i < in) {
                a.append("X");
                i++;
            }
            return a.toString();
        }
        else return "";
    }
    // преобразовываем пол тысячи
     private static String D(int in) {

        if (in = 4) return "CM"; // если 900, то 1000-100
        else  return "D";
    }


    private static String L(int in) {
        if (in = 4) return "XC"; / / если90 то100 - 10
                 return "L";

            }
            // От 1 до 9, то что осталось
            private static String basic(int in) {
                String[] a = {
                    "",
                    "I",
                    "II",
                    "III",
                    "IV",
                    "V",
                    "VI",
                    "VII",
                    "VIII",
                    "IX"
                };
                return a[in];
            }

        }
</code>

P.S.: Уже в процессе написания подумал что стоить реализовать обратное преобразование.
Tags:
Hubs:
0
Comments 8
Comments Comments 8

Articles