Комментарии 45
А где же у вас валидация правильности записи числа?
Если речь про результат работы toRoman, то его можно проверить несколькими способами:
Прогнать через любой другой обратный конвертер (можно даже через тот, что имплементирован в том же репозитории)
Преобразовать число обратно руками, правила не столь сложные
В том же репозитории есть регулярка проверки римского числа на валидность
Не могу не поделиться своей уже достаточно давней реализацией
Тоже очень хотел сделать простое добавление «новых цифр» и понятную сложность
Выглядит неплохо, кста!
Мне не сразу стало понятно, что это за гимнастика с округлениями и условиями, но немного обмозговав, все теперь выглядит кристально чисто, кроме странной итерации.
Если в какой-то момент осознать, что уникальных чисел в римской нумерации всего 3, то все становится немного проще:
"I"
"V"
"X"
А если осознать, что их больше
L 50
C 100
D 500
M 1000
то все снова станет немного сложнее)))
Переведите для идиотов фразу "Например, "CM" это всего лишь "IX" , то есть умножение происходит на ту степень, в какой позиции мы ожидаем это число увидеть в арабской записи "
На этой фразе ведь весь смысл статьи держится, не так ли?
Например, "CM" это всего лишь "IX"
, то есть умножение происходит на ту степень, в какой позиции мы ожидаем это число увидеть в арабской записи
то есть 900 это 9*10^2, это здорово, но мы это знаем, что это даёт в контексте статьи?
Откройте почти любую реализацию перевода чисел из арабской системы в римскую и вы почти со 100% вероятностью увидите там знаменитые дифтонги "CM" (900), "CD" (400) и так далее. И поначалу кажется, что без них не обойтись. Но это не так!
и в финале статьи вы пишете "Итого, 4956 превратится "MMMMCMLVI" ", что ставит в тупик, я ожидал какое-то решение где CM и CD не будет.
CM и CD если я правильно понимаю нельзя выкинуть просто так, если и можно записать как-то по другому числа, это будет неправильная запись.
Тут суть я так понимаю в том, что в "стандартном подходе" алгоритм выглядит как-то так:
Число разбивается по цифрам и в зависимости от разрядности добавляются нужные буквы, а тут процесс "парсинга" по другому идет
Мы не захардкодили значение этого “CM”, а нашли его, вывели правило, по которому строятся числа в римской нумерации с этим правилом off by one.
Римская нумерация работает так, что нужны эти сочетания. Просто они не обязательны в решении
я читаю правила написания в вики и не понимаю о чем конкретно ваша статья и почему обозначена какая-то проблема? какая кстати?
Проблема заключается в том, что нельзя просто так полагаться на сочетания букв и использовать не атомарные значения, чем грешат прочие реализации с их “CM” (900), “IV” (4) etc. Зачем они нужные, если они выводятся из базовых значений “C”, “M”, “I”, “V”?
На Leetcod-e задача "Roman to integer" идёт в первой двадцатке и помечена как лёгкая. На том же Leetcod-е на текущий момент приведено 17.4К вариантов решений на разных языках программирования.
Вопрос: для чего писать отдельную статью?
Начнем с того, что это не Roman to integer, а Integer to roman, а эта проблема на Leetcode имеет уже отметку медиум.
Вдобавок, в тех решениях все так же присутствуют дифтонги. Прелесть этого решения в том, что тут не надо иметь пары букв, только атомарные значения
Вдобавок, варианты реализаций через запоминание дифтонгов плохо масштабируются, если кому-либо когда-либо захочется расширить домен римских чисел сверх 5000.
Вот тут не понял. Почему они плохо масштабируются, если всё, что для этого надо сделать, – добавить числа из расширения (вместе с новыми дифтонгами) в рабочий массив?
Пожалуйста, не называйте дифтонгами то, что ими не является. Дифтонги - это вообще не про буквы.
А здесь, это просто придумать буквы, взять следующие значения (5000, 10000) и все.А всё уже придумано. На каждые следующие три десятичных разряда просто добавляется одна черта сверху.
![image](https://habrastorage.org/webt/pp/mi/wd/ppmiwdxeewhesgmydwzugvbfkbm.png)
Но при этом 1000, 2000 и 3000 обозначаются как M, MM и МММ, а не I̅, I̅I̅ и I̅I̅I̅.
На каждые следующие три десятичных разряда
В римской системе есть десятичные разряды?
Конечно, есть. Вы же X от I как-то отличаете?
Римские цифры соответствуют некоторым числам. Эти числа в арабской записи могут занимать некоторое количество десятичных разрядов. А так римская система на степени 10 не сильно завязана.
</зануда> ;)
Разряды есть, просто нет явного обозначения нуля каким-либо символом.
А всё уже придумано
А это правда нативная римская запись, с черточками? Римлянам действительно не хватало букв? или новодел?
Римляне изначально (где-то за 700-800 лет до нашей эры) использовали другие символы:
ↆ — 50, Ↄ — 100, D или IↃ — 500, ↀ или CIↃ — 1000, ↁ или IↃↃ — 5000, ↂ или CCIↃↃ — 10000, ↇ или IↃↃↃ — 50000, ↈ или CCCIↃↃↃ — 100000.
Вариант с чертой появился примерно в начале нашей эры, но и в XVI веке обе системы ещё использовались одновременно.
Кроме того, принцип вычитания для 4 и 9 использовался не всегда и встречаются записи вида XLIIII (44). Окончательно он утвердился только в XIX веке.
85674 — IↃↃↃCCIↃↃCCIↃↃCCIↃↃIↃↃIↃCↆXXIIII или ↇↂↂↂↁDCLXXIIII или L̅X̅X̅X̅V̅DCLXXIV.
Вы забыли упомянуть, что у некоторых авторов могли надчёркиваться вообще все числа, и черта там просто выделяла число на фоне текста.
для математических целей
Кстати, а что с математическими операциями у римлян? Что они с этими числами потом делали? Если бы не IV/IX — сложение выглядело бы достаточно просто: сосчитал символы в слагаемых, выписал рядом. Если одинаковых символов >4 — перенос в следующую группу. А так, сложение-вычитание в столбик достаточно сложное, умножение/деление — почти решение дифуров ;)
Вместо записи IV зачастую использовали IIII, вместо IX — VIIII, так что способ с количеством вполне подходит.
126 * 37 = CXXVI * XXXVII
Умножаем на каждую цифру:
CXXVI * X = MCCLX
CXXVI * X = MCCLX
CXXVI * X = MCCLX
CXXVI * V = DLLXXVV = DLLXXX = DCXXX
CXXVI * I = CXXVI
CXXVI * I = CXXVI
Складываем и объединяем:
MMMDCCCCCCCCCLLLXXXXXXXXXXVVII =(VV => X) MMMDCCCCCCCCCLLLXXXXXXXXXXXII =(XXXXX => L) MMMDCCCCCCCCCLLLLLXII =(LL => C) MMMDCCCCCCCCCCCLXII =(CCCCC => D) MMMDDDCLXII =(DD => M) MMMMDCLXII = 4662
Что они с этими числами потом делали?
Считали на абаке. Запись использовалась только для хранения.
Считали на абаке.
Действительно, для перекладывания шариков из верхней ячейки в нижнюю эта система отлично подходит ;) И шариков нужно меньше чем для десятичных счет.
![image](https://habrastorage.org/webt/jh/i9/4h/jhi94hzwtsj7ce7qcextkom7o10.jpeg)
А вы уверены, что 4956 - это MMMMCMLVI, а не MMMMLMVI?
Когда-то давно на codewars такое решение придумал
Значения захардкожены, конечно, но сам алгоритм простой получается
function intToRoman(num: number): string {
const roman = ['I', 'IV', 'V', 'IX', 'X', 'XL', 'L', 'XC', 'C', 'CD', 'D', 'CM', 'M'];
const numbers = [1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000];
let result = '';
let i = numbers.length;
while(num) {
if (num >= numbers[i]) {
result += roman[i];
num -= numbers[i];
} else {
i--;
}
}
return result;
};
Уважаемый автор, к сожалению, название статьи выбрано не вполне корректно.
Речь в статье идёт о согласных, а дифтонги по определению - это "сочетание не разделённых согласными двух гласных звуков в одном слоге."
Примеры можно найти в том же латинском языке, а также в немецком и других.
Римские числа или как не запоминать составные варианты