Zanurkuj w Pythonie/Wprowadzenie do liczb rzymskich

Wprowadzenie do liczb rzymskich

edytuj

W poprzednich rozdziałach "nurkowaliśmy" poprzez bezpośrednie przyglądanie się kodowi, aby zrozumieć go tak szybko, jak to możliwe. Teraz, gdy już trochę poznaliśmy Pythona, trochę się cofniemy i spojrzymy na kroki, które trzeba wykonać przed napisaniem kodu.

Kilka rozdziałów wcześniej pisaliśmy, debugowaliśmy i optymalizowaliśmy zbiór użytecznych funkcji, które służyły do konwersji z i na liczby rzymskie. W Podrozdziale 7.3, "Analiza przypadku: Liczby rzymskie", opisaliśmy mechanizm konstruowania i sprawdzania poprawności liczb w zapisie rzymskim, lecz teraz cofnijmy się trochę i zastanówmy się, co moglibyśmy uwzględnić, aby rozszerzyć to narzędzie, by w dwóch kierunkach.

Zasady tworzenia liczb rzymskich prowadzą do kilku interesujących obserwacji:

  1. Istnieje tylko jeden poprawny sposób reprezentowania pewnej liczby w postaci rzymskiej.
  2. Odwrotność też jest prawdą: jeśli ciąg znaków jest poprawną liczbą rzymską, to reprezentuje ona tylko jedną liczbę (tzn. możemy ją przeczytać tylko w jeden sposób).
  3. Tylko ograniczony zakres liczb może być zapisany jako liczby rzymskie, a dokładniej liczby od 1 do 3999 (Liczby rzymskiej posiadają kilka sposobów wyrażania większych liczb np. poprzez dodanie nadkreślenia nad cyframi rzymskimi, co oznacza, że normalną wartość tej liczby trzeba pomnożyć przez 1000, jednak nie będziemy się wdawać w szczegóły. Dla potrzeb tego rozdziału, założymy, że liczby rzymskie idą od 1 do 3999).
  4. Nie mamy możliwość zapisania 0 jako liczby rzymskiej. (Co ciekawe, starożytni Rzymianie nie wyobrażali sobie 0 jako liczby. Za pomocą liczb liczymy, ile czegoś mamy, jednak jak możemy policzyć coś, czego nie mamy?)
  5. Nie możemy w postaci liczby rzymskiej zapisać liczby ujemnej.
  6. W postaci liczby rzymskiej nie możemy zapisywać ułamków, czy liczb, które nie są całkowite.

Biorąc to wszystko pod uwagę, co możemy oczekiwać od zbioru funkcji, które konwertują z i na liczby rzymskie? Wymagania roman.py:

  1. toRoman powinien zwracać rzymską reprezentację wszystkich liczb całkowitych z zakresu od 1 do 3999.
  2. toRoman powinien nie zadziałać (ang. fail), gdy otrzyma liczbę całkowitą spoza przedziału od 1 do 3999.
  3. toRoman powinien nie zadziałać, gdy otrzyma niecałkowitą liczbę.
  4. fromRoman powinien przyjmować poprawną liczbę rzymską i zwrócić liczbę, która ją reprezentuje.
  5. fromRoman powinien nie zadziałać, kiedy otrzyma niepoprawną liczbę rzymską.
  6. Kiedy daną liczbę konwertujemy na liczbę rzymską, a następnie z powrotem na liczbę, powinniśmy otrzymać tę samą liczbę, z którą zaczynaliśmy. Więc dla każdego n od 1 do 3999 fromRoman(toRoman(n)) == n.
  7. toRoman powinien zawsze zwrócić liczbę rzymską korzystając z wielkich liter.
  8. fromRoman powinien akceptować jedynie liczby rzymskie składające się z wielkich liter (tzn. powinien nie zadziałać, gdy otrzyma wejście złożone z małych liter).