Berechnung römischer zahlen in ganze zahlen
-
leech schrieb:
das sollte nur für Matar verdeutlichen, wie das programm das rechnet... wenn die aktuelle ziffer kleiner ist als die folgende, dann subtrahiert er die ziffer, ansonsten addiert er sie hinzu... zumal es doch auch egal ist, wie man es aufschreibt... ein mathematisches gesetzt (mir fällt der name gerade nicht ein) besagt doch, dass -100 + 500 == 500 - 100... beides ist 400... von daher ists doch eigentlich egal... naja.. ich will mich darum jetzt auch nicht streiten
es ist nicht egal, wie man es aufschreibt. wenn du es so aufschreibst, denkst du nicht so, wie es die schreibweise verlangt. es wäre imo logischer, selbst richtig zu denken und das dann umzusetzen, statt etwas umzusetzen, daß gerade mal dasselbe tut.
-
Stimmt, ich hab leider nicht bedacht das die Zweitgrößte Ziffer auch ne Rolle spielen kann.
Dennoch finde ich meinen Ansatz schöner als den wo man von der aktuellen und folgenden Ziffer ausgeht. Ich werde morgen mal sehen ob ichs richtig hin bekomme.
-
Ok, ich habs hin bekommen. Aber ich muß schon sagen, diese Problemstellung hörte sich zu Anfang wesentlich einfacher an als sie letzendlich ist. Würde mich wundern wenn Matar den Quellcode hier noch versteht.
Falls doch, respekt.
#include <iostream> #include <string> using namespace std; //globale Variablen deklarieren. int positionOfBiggestNumeral; int currentPosition; enum numerals { I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000 }; numerals currentNumeral; //Funktion zum Umwandeln einer römischen in eine arabische Zahl. //Der erste Parameter ist die Zeichenkette in der die römische //Zahl gespeichert wird. Der zweite Parameter ist eine Referenz //auf den Integer in dem die arabische Zahl gespeichert wird. int latin2arabic(string latin, int &arabic) { //Position der größten Ziffer bestimmen. if (latin.find("M") != -1) { positionOfBiggestNumeral = latin.find("M"); } else if (latin.find("D") != -1) { positionOfBiggestNumeral = latin.find("D"); } else if (latin.find("C") != -1) { positionOfBiggestNumeral = latin.find("C"); } else if (latin.find("L") != -1) { positionOfBiggestNumeral = latin.find("L"); } else if (latin.find("X") != -1) { positionOfBiggestNumeral = latin.find("X"); } else if (latin.find("V") != -1) { positionOfBiggestNumeral = latin.find("V"); } else if (latin.find("I") != -1) { positionOfBiggestNumeral = latin.find("I"); } else { positionOfBiggestNumeral = 0; } //Jede Ziffer der römischen Zahl durchgehen. for (currentPosition = 0; currentPosition <= positionOfBiggestNumeral; currentPosition++) { //Wert der aktuellen Ziffer bestimmen. switch (latin[currentPosition]) { case 'I': currentNumeral = I; break; case 'V': currentNumeral = V; break; case 'X': currentNumeral = X; break; case 'L': currentNumeral = L; break; case 'C': currentNumeral = C; break; case 'D': currentNumeral = D; break; case 'M': currentNumeral = M; break; default : //Gibt bei ungültiger Eingabe fühzeitig return 1; //an die Main-Funktion zurück. } //Arabische Zahl dem Kontext entsprechend um den Wert der //aktuellen Ziffer dekrementieren oder inkrementieren. if (currentPosition < positionOfBiggestNumeral) { arabic -= currentNumeral; } else { arabic += currentNumeral; } } if (positionOfBiggestNumeral == latin.length() - 1) { //Gibt an die Main-Funktion zurück, wenn die größte römische //Ziffer die Letzte ist. return 0; } else { //Ansonsten ruft sich die Funktion latin2arabic() selbst //auf (rekursiv). Und übergibt den Teil hinter der größten //römischen Ziffer an den neuen Aufruf von latin2arabic() //und gibt dessen Wiedergabe Wert an Main() zurück. return latin2arabic(latin.substr(positionOfBiggestNumeral + 1, latin.length() - positionOfBiggestNumeral), arabic); } } //Hauptprogramm. int main() { //lokale Variablen deklarieren. string latin; int arabic = 0; //Römische Zahl abfragen. cout << "Geben Sie eine r\x94mische Zahl ein." << endl; cin >> latin; if (latin2arabic(latin, arabic) == 0) { //Gibt nach erfolgreicher Ausführung der Funktion //latin2arabic() die arabische Zahl aus. cout << "Die arabische Zahl lautet: " << arabic << endl; } else { //Gibt eine Fehlermeldung aus, wenn die Funktion nicht //erfolgreich beendet wurde. cout << "Die eingegebene Ziffer ist ung\x81ltig." << endl; } //Betätigung abwarten und Programm beenden. system("PAUSE"); return 0; }
-
für jemanden, der schon länger unter c++ programmiert ist das kein problem... doch ich glaube, dass sich Matar bei dem code wirklich schwer tun wird... aber es rekursiv zulösen ist auch gut...mal gucken, ob Matar es versteht... und wenn nicht, auch nicht so schlimm.. das lernt er noch alles..
-
Hi!
Es gibt bei den römischen Zahlen zwei Regeln. Die eine benutzt eine kurze Schreibweise. Halt so kurz es geht mit den bekannten Anwendungen, z.B: 99 = IC. Es gibt aber eine weitere nach der die römischen Zahlen in 1000er, 100er, 10er und 1er zerlegt werden, somit wäre 99 = XCIX.
Das war in meiner Ausbildung nach dem ersten Jahr für einige eine Abschlussarbeit. Ich habe dabei 2 Programme entworfen gehabt, die nach beiden Regeln rechnen konnten. Habe die aber leider nicht mehr, da ich den Ordner mal vergessen habe zu sichern.
Habe dazu aber auch ne ganz gute Seite gefunden:
http://www.diaware.de/html/roemzahl.html
Unten ist eine Tabelle, wo beide Schreibweisen nochmal stehen.
Ansonsten sind Konstelationen wie VIC nicht erlaubt, da die einzelnen Zeichen nicht nach absteigender Wertigkeit angeordnet sind. Diese Regel gilt für beide o.g. Regeln.Code-Hacker
-
Also mein Programm evaluiert sowohl IC als auch XCIX zu 99.
Ach übrigens, ich programmier C++ auch erst seit nem Monat.
-
wie schon gesagt, bei "hello world" hörts erstmal bei mir auf
also bei leechs erstem versuch kam ich noch ein bisschen mit, aber schrankwands werk ist nur noch "leicht verständlich". macht aber nix, wird glaub ich so schnell noch nicht von mir in der uni verlangt .. die erklären uns gerade was if und else ist und das versteh ich noch
-
Zu Schrankwands Lösung:
Ich sehe keinen großen Sinn im enum, da für die simple Zuweisung im switch-Block auch die Integer-Werte gereicht hätten. Ich würde eher die ganze String-Sucherei davor angehen, indem man z.B. die römischen Ziffern als Schlüssel in eine std::map packt. Das würde sowas in der Art ermöglichen:std::map<char, int> roman; roman['I'] = 1; // etc. // ... for (int i = 0; i < str.length() - 1; ++i) { actual = roman[str[i]]; next = roman[str[i+1]]; if (next > actual) summe -= actual; else summe += actual; }
Ungültige Kombinationen (d.h. größere Ziffern haben nach rechts einen größeren Abstand als 1 zur aktuellen Position) müßten zwar auch hier noch gefiltert werden, aber so ist's IMHO schon besser lesbar.
-
Vielleicht wäre es tatsächlich besser anstatt eines enum, eine map zu nehmen, aber ansonsten, ist dein Beispielcode mit dem meines Vorgängers äquivalent und berücksichtigt d.h. keinerlei Problemstellung die ich in meinem Quellcode gelöst habe und ist somit auch nicht in der Lage jede beliebige römische Zahl in eine Arabische umzuwandeln.
-
Hmm? Weiß nicht, was du meinst. Hatte heut Langeweile in der Vorlesung, da hab ich meinen Ansatz mal ausgeschrieben, und es funzt wunderbar. Die meisten ungültigen Nummern filtert er auch, außer Sauereien wie MCMCMCM, wobei ich mir nicht sicher bin, ob eine solche Nummer auch wirklich ungültig ist. Für einige gibt es nunmal mehrere Kombinationen...
#include <string> #include <map> #include <iostream> using namespace std; int main() { map<char, int> cyphers; cyphers['I'] = 1; cyphers['V'] = 5; cyphers['X'] = 10; cyphers['L'] = 50; cyphers['C'] = 100; cyphers['D'] = 500; cyphers['M'] = 1000; cyphers['i'] = 1; cyphers['v'] = 5; cyphers['x'] = 10; cyphers['l'] = 50; cyphers['c'] = 100; cyphers['d'] = 500; cyphers['m'] = 1000; cout << "roman (upper case): "; string roman; cin >> roman; int total = 0, actual; for (size_t i = 0; i < roman.length() - 1; ++i) { actual = cyphers[roman[i]]; int next = cyphers[roman[i+1]]; // ungueltiges Zeichen oder illegale Anordnung if ( !actual || !next || (i > 0 && next > cyphers[roman[i-1]]) ) { cout << "invalid number!" << endl; return 1; } if (actual < next) total -= actual; else total += actual; } if (!(actual = cyphers[roman[i]])) { cout << "invalid number!" << endl; return 1; } total += actual; cout << "arabic: " << total << endl; }
-
Also dazu will ich auch mal was sagen! Ich weiß nicht ob ich nen denkfehler hab, aber warum macht ihrs euch so schwer?
tstring latin_tchars("iIvVxXlLcCdDmM"); void erase_wrongs (tstring& s) { size_t pos=s.find_first_not_of(latin_tchars); bool fls=false; for(;pos!=tstring::npos;pos=s.find_first_not_of(latin_tchars)) { s.erase(pos,1); fls=true; }; if(fls) cout<<"Fehleingabe/n (wurden ignoriert)"<<endl; }; int digit_to_number(tchar a) { switch(a) { case 'i': case 'I': return 1; case 'v': case 'V': return 5; case 'x': case 'X': return 10; case 'l': case 'L': return 50; case 'c': case 'C': return 100; case 'd': case 'D': return 500; case 'm': case 'M': return 1000; default: return -1; }; }; int latin_arabian(tstring& input) { erase_wrongs(input); //input gesäubert int output=0; //Ausgabe if(input.size()==1) return digit_to_number(input[0]); else { int current_digit; int next_digit=digit_to_number(input[0]); for(unsigned int i=0;i<input.size();++i) { current_digit=next_digit; next_digit=digit_to_number(input[i+1]); if(i==input.size()-1) { output+=current_digit; return output; } else { if(current_digit<next_digit) output-=current_digit; else output+=current_digit; }; }; }; return output; };
Am umgekehrten weg kämpf ich noch, machs mir glaub ich zu schwer...
OK, das von Covaine ist noch kürzer, aber für einen anfänger leichter verständlich ist meins, oder?
Falls das jemand kompileren will muss er tstring string und tchar durch char ersetzen...
-
Hello! gbbcbfa interesting gbbcbfa site!