Programátorské úlohy 1. – Římská čísla

Když člověk začíná s programováním, mívá problém, že neví co programovat. Proto zde budu postupně uvádět různé úlohy na které jsem někde narazil. Samozřejmě uvedu i jedno z mnoha možných řešení. Doporučuju úlohy řešit nejdříve samostatně, pokud si nebudete vědět rady, podívejte se na nápovědu. No a pokud ani nápověda nepomůže, nakonec dodám i kompletní zdrojový kód (v jazyce C++).

Takže začneme:
V první úloze se pokusíme převádět čísla z normálních (arabských) číslic do číslic římských a naopak.

Nejdříve si povíme něco o římských číslicích

Wikipedie říká:
Používání římských číslic v matematice bylo zastaralé již před více jak 1100 lety. Přesto se římské číslice používají při různých příležitostech dodnes. Římské číslice se používají pro číslice na hodinovém ciferníku, číslují se tak stránky předmluvy v knihách, používají při číslování položek, kapitol v knihách, pořadí panovníků, filmových nebo knižních děl apod.

Způsob zapisování římských číslic vznikl ve středověku v západní Evropě. Je odvozen ze způsobu, jakým zapisovali číslice staří Římané, ale obsahuje některá vylepšení. Základní římské číslice používané dnes jsou:

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

Spojováním a opakováním základních symbolů lze zapisovat i větší čísla. Větší číslice vždy předcházejí menší. Proto např. VI je 6, CLXXIII je 173 a MDCCCXXII je 1822.

Římané obvykle psali číslo 4 jako IIII, číslo 40 jako XXXX, číslo 999 jako DCCCCLXXXXVIIII.

Ke zkrácení zápisu takových dlouhých čísel se někdy používalo zvláštního pravidla pro odečítání a teprve ve středověku se toto pravidla stalo obecně používaným. Pravidlo pro odečítání umožňuje použití šesti složených symbolů, ve kterých menší číslice přechází větší:

IV = 4
IX = 9
XL = 40
XC = 90
CD = 400
CM = 900

Konec citace z wikipedie

Zadání úlohy

Vytvořte program, který dá uživateli možnost k převodu mezi arabskými číslici na římské a naopak. Taky nezapomeňte nabídnout možnost program ukončit. Počítá se s čísly menšími než 3999.

Nápověda

Pro převod z normálních čísel do římských je třeba normální číslo rozkouskovat na tisíce, stovky, desítky a jednotky. Začněte tísícema, a končete jednotkami. Takže pokud třeba bude na místě tisíců číslovka 2 (třeba v čísle 2465), převedete dvojku na MM. Zbytek převodu je myslím jasný.

Převod z římských čísel do normálních (arabských) čísel je o poznání jednodušší. Stačí číst znak po znaku, a každý znak převést na číselnou hodnotu (např. M=1000, nebo V=5). Tyto hodnoty sčítejte, ale pozor! Pokud bude hodnota následujícího znaku větší než aktuální znak, nezapomeňte tyto znaky od sebe odečíst. Je to potřeba, aby se správně převedly i znaky vzniklé zkracováním (například XL, nebo CD).

Kompletní řešení – zdrojový kód

Pokud jste se dostali až sem, předpokládám že si nevíte rady. Pokud jste ještě nad problémem nepřemýšleli, raději následující řádky nečtěte. Uvedené řešení určitě nepatří mezi nejlepší, ale co je hlavní – funguje to.

Funkce na převod arabských čísel na čísla římská:

void ArabToRoman(long x, char * roman)
{
//fce prebira dva parametry - cislo v normalnim tvaru
        //a ukazatel na retezec, ktery se potom
        //naplni cislem v rimskych cislicich
        long xx[4] = {0}; //pole obsahujici pocet tisicu,
                                  //stovek, desitek a jednotek
        int i = 0;
while (x != 0) //naplneni pole
        {
xx[3-i] = x % 10;
x = x / 10;
i++;
};
int ii = 0; // pozice v poli s cislicemi
        int pos = 0; //pozice v retezci na kterou se budou zapisovat znaky
        //v tomto cyklu se budou pocitat zvlast tisice, stovky, desitky, jednotky
         while (ii < 4 && ii >= 0)
{
if (xx[ii] > 0 && ii == 0)  //nejprve se zjisti tisice
                        for (pos = 0; pos < xx[ii]; pos++)
roman[pos] = 'M';
if (xx[ii] > 0 && ii == 1) //potom stovky
                {
//aby se nezacinalo zapisovat od nulte pozice,
                       // zacina se od pos do pos_temp
                        int pos_temp = pos + xx[ii];
if (xx[ii] <=3)
for (pos; pos < pos_temp; pos++)
roman[pos] = 'C';
else if (xx[ii] == 4)
{
roman[pos++] = 'C';
roman[pos++] = 'D';
}
else if (xx[ii] == 5)
roman[pos++] = 'D';
else if (xx[ii] > 5 && xx[ii] <= 8)
{
roman[pos++] = 'D';
for (pos; pos < pos_temp-4; pos++)
roman[pos] = 'C';
}
else if (xx[ii] == 9)
{
roman[pos++] = 'C';
roman[pos++] = 'M';
};

};
if (xx[ii] > 0 && ii == 2) //pak desitky
                {
int pos_temp = pos + xx[ii];
if (xx[ii] <=3)
for (pos; pos < pos_temp; pos++)
roman[pos] = 'X';
else if (xx[ii] == 4)
{
roman[pos++] = 'X';
roman[pos++] = 'L';
}
else if (xx[ii] == 5)
roman[pos++] = 'L';
else if (xx[ii] > 5 && xx[ii] <= 8)
{
roman[pos++] = 'L';
for (pos; pos < pos_temp-4; pos++)
roman[pos] = 'X';
}
else if (xx[ii] == 9)
{
roman[pos++] = 'X';
roman[pos++] = 'C';
};

};
if (xx[ii] > 0 && ii == 3) // a nakonec jednotky
                {
int pos_temp = pos + xx[ii];
if (xx[ii] <=3)
for (pos; pos < pos_temp; pos++)
roman[pos] = 'I';
else if (xx[ii] == 4)
{
roman[pos++] = 'I';
roman[pos++] = 'V';
}
else if (xx[ii] == 5)
roman[pos++] = 'V';
else if (xx[ii] > 5 && xx[ii] <= 8)
{
roman[pos++] = 'V';
for (pos; pos < pos_temp-4; pos++)
roman[pos] = 'I';
}
else if (xx[ii] == 9)
{
roman[pos++] = 'I';
roman[pos++] = 'X';
};

};
ii++;
};
// nakonec vyplnim zbytek retezce nulovymi znaky
        for (int i = pos; i <= size; i++)
roman[i] = '\0';
}

Z komentářů by mělo být jasné, jak to funguje. Dále přiložím proceduru na opačný převod – z římských čísel do arabských:

void RomanToArab(char * roman, long & x)
{
//Tato funkce prebira dva parametry, jeden je retezec s rimskymi cislicemi
        //a druhy je cislo, do ktereho ulozime vysledek, jelikoz je predan odkazem
        //pracuje funkce primo s puvodni promenou
        x = 0;
long cislo[size]={0};
int i = 0;
//Nejdrive vytvorim pole cislo, ktere naplnim ciselnymi hodnotami
        //jednotlivych znaku
        while (roman[i])
{
switch(roman[i])
{
case 'm':
case 'M': cislo[i] = 1000;
break;
case 'd':
case 'D': cislo[i] = 500;
break;
case 'c':
case 'C': cislo[i] = 100;
break;
case 'l':
case 'L': cislo[i] = 50;
break;
case 'x':
case 'X': cislo[i] = 10;
break;
case 'v':
case 'V': cislo[i] = 5;
break;
case 'i':
case 'I': cislo[i] = 1;
break;
default: cislo[i] = 0;
};
i++;
};
i = 0;
//A nakonec nezbyva nez poscitat jednotlive polozky pole cislo
        //pokud je nasledujici cislo vetsi, tak aktualni cislo odectu
        //pokud je nasledujici cislo mensi, tak to aktualni cislo prictu
        while (cislo[i])
{
if (cislo[i+1]>cislo[i])
x -= cislo[i];
if (cislo[i+1]<=cislo[i])
x += cislo[i];
i++;
};
}

A nakonec přiložím kompletní zdrojový soubor, pro stažení klikněte ZDE.

Pokud máte nějaký dotaz, nebo vám něco z toho není jasné, klidně se ptejte. Od čeho by tu jinak byly komentáře 😉

Příspěvek byl publikován v rubrice Různé. Můžete si uložit jeho odkaz mezi své oblíbené záložky.

15 komentářů: Programátorské úlohy 1. – Římská čísla

  1. Petr napsal:

    Mám takový problém. Když to zkopíruju do c++ a spustim to tak mi to hodí pár chyb, ale nedokážu je najít. Sem co se týče těchto věcí začátečník. Mohl bych poprosit o zaslání komplentního zdrojáku na můj mail?? předem děkuju.

  2. Mirek napsal:

    V kodu postradam definici promnenne SIZE a pokud by to mel byt predpokladam int tak pak
    long cislo[size]={0};
    nebude fungovat viz. staticka a dynamicka definice pole

  3. dadajax napsal:

    Mirek: děkuji za opravení, opravdu jsem tam proměnou size zapomněl definovat.

  4. mc napsal:

    Mohl bych poprosit o zaslání zdrojáku na mail? Mám za ukol obdobný projekt a docela v tom plavu..:-/ odkaz v článku nefunguje..

  5. Seff napsal:

    poprosil bych o zaslani zdrojoveho kodu na muj email, pokud by to slo. diky

  6. Azimut napsal:

    Hmm, neco podobneho jsem ted delal v jave, akorat zadani bylo: Prevedte cisla na slova v intervalu od -10 000 000 000 do 10 000 000 000. Tohle se mi zda je neco podobnyho, ale urcite zkusim. Diky za podnet

  7. Kristina napsal:

    Mohla bych poprosit o zaslání kompletního zdrojáku na mail?? mám něco obdobného za úkol a moc netuším co s tím. A odkaz na těchto stránkách nefunguje.
    Díky moc.

  8. Jonathan napsal:

    Ahoj. Mohol by som poprosit o poslatie zdrojoveho kodu na mail? pripadne upnutie na nejaky server? Dakujem

  9. nasrat napsal:

    no těch chybyček je tady poněkud více, tenhle program nemohl nikdy fungovat…zajímalo by mě, z jakého webu autor zdroják zkopíroval, a zda-li tenhle program vůbec někdy zkoušel napsat….strašný fakt že jo, je to dobrý koncept, ale né hotový program..

  10. ivett napsal:

    Chtěla bych poprosit o zaslání zdrojového kódu na mail, pokud je to možné. Odkaz na něj nefunguje… Mám za úkol udělat závěrečný projekt – „Převod římského letopočtu na náš a obráceně“ a moc tomu nerozumím… Velmi moc by mi to pomohlo a moc předem děkuji!

  11. Fikus napsal:

    prosím o zasláni zdrojového kodu, děkuji

  12. DrTom napsal:

    Prosím o zaslání zdrojového kodu na mail, děkuji

  13. ufon009 napsal:

    Mohl by mi někdo prosím poslat zdroják na mail?odkaz je nefunkční..díky

  14. simon napsal:

    Ahojte… nemohol by si mi poslat kompl. zdrojovy kod ???

  15. jana napsal:

    Mohla bych taky poprosit o zaslání kompletního zdrojáku na mail? Sem záčatečník, a mám něco obdobného za úkol a moc netuším co s tím.
    Díky moc za pomoc.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.