Berechnung römischer zahlen in ganze zahlen
-
hi, da ich gerade erst mein studium aufgenommen habe und nun mit c++ konfontiert werde von dem ich besiher noch nicht viel gehört habe, sitze ich nun eifrig um wenigstens etwas von dozenten zu verstehen.
dabei hat er mal eine beispielaufgabe angegeben, die uns lehren soll einen top-down entwurf anzufertigen.
es geht darum, die römischen ziffern ( I, V, X, L, C, D, M ) anhand einer kette einzulesen und dann diese in zahlen auszudrücken.leider reicht mein wissen der sprache nicht viel weiter als das hello world programm :).
wie kann ich es also schaffen aus einem wort ( römische zahlen sollen eingegeben werden cin>>kette ) diese Zeichen auszulesen und dann berechnen zu lassen.
ich hab es in einer simpleren variante mit switch() versucht, das jede einzelne römische zahl einzeln eingegeben wird, aber selbst da lag wohl der wurm drinnen:
#include <iostream> using namespace std; int main() { int r1,r2,r3,r4,r5,anz; const double I=1,V=5,X=10,L=50,C=100,D=500,M=1000; system("cls"); cout<< "\t\tProgramm zur Berechnung Roemischer Zahlen in Ganze Zahlen \n" << "\t\tmax. 5 Zahlen\n\n\n"; cout<< "\n\t\tWieviel Zahlen sollen hinzugefuegt werden?";cin>>anz; switch(anz) { case 1: system("cls"); cout<< "\nGeben sie die "<<anz<<". roemische Zahl ein: ";cin>>r1; if(r1==I) cout<<I; break; case 2: system("cls"); cout<< "\nGeben sie die "<<anz<<". roemische Zahl ein: ";cin>>r1; cout<< "\nGeben sie die "<<anz+1<<". roemische Zahl ein: ";cin>>r2; cout<< "\n\n "<<r1+r2; break; case 3: system("cls"); cout<< "\nGeben sie die "<<anz<<". roemische Zahl ein: ";cin>>r1; cout<< "\nGeben sie die "<<anz+1<<". roemische Zahl ein: ";cin>>r2; cout<< "\nGeben sie die "<<anz+2<<". roemische Zahl ein: ";cin>>r3; cout<< "\n\n "<<r1+r2+r3; break; case 4: system("cls"); cout<< "\nGeben sie die "<<anz<<". roemische Zahl ein: ";cin>>r1; cout<< "\nGeben sie die "<<anz+1<<". roemische Zahl ein: ";cin>>r2; cout<< "\nGeben sie die "<<anz+2<<". roemische Zahl ein: ";cin>>r3; cout<< "\nGeben sie die "<<anz+3<<". roemische Zahl ein: ";cin>>r4; cout<< "\n\n "<<r1+r2+r3+r4; break; case 5: system("cls"); cout<< "\nGeben sie die "<<anz<<". roemische Zahl ein: ";cin>>r1; cout<< "\nGeben sie die "<<anz+1<<". roemische Zahl ein: ";cin>>r2; cout<< "\nGeben sie die "<<anz+2<<". roemische Zahl ein: ";cin>>r3; cout<< "\nGeben sie die "<<anz+3<<". roemische Zahl ein: ";cin>>r4; cout<< "\nGeben sie die "<<anz+4<<". roemische Zahl ein: ";cin>>r5; cout<< "\n\n "<<r1+r2+r3+r4+r5; break; default: system("cls"); cout<< "\nKeine gueltige Eingabe!";system("pause");main(); break; } system("pause"); return 0; }
schonmal vielen dank für antworten
mfg
Matar
-
bis jetzt habe ich nur die folgende lösung.... sie muss aber noch verbessert werden... das ist dann deine aufgabe... ich hoffe, dass dir der folgende code ein bisschen hilft... wenn nicht, dann frag noch mal nach...
#include <iostream> using namespace std; int main() { string kette; cout << "Bitte geben Sie eine Kette bestehend aus roemischen Zahlen ein: "; cin >> kette; int laenge = kette.size(); int zahl = 0; for(int i = 0; i < laenge; i++) switch(kette[i]) { case 'I': case 'i': zahl += 1; break; case 'V': case 'v': zahl += 5; break; case 'X': case 'x': zahl += 10; break; case 'L': case 'l': zahl += 50; break; case 'C': case 'c': zahl += 100; break; case 'D': case 'd': zahl += 500; break; case 'M': case 'm': zahl += 1000; break; default: //Wenn man eine falsche Ziffer eingibt... cout << "Unbekannte Ziffer!" << endl; } cout << "Diese Zahl ist: " << zahl << endl; cin.get(); cin.get(); return 0; }
P.S.: Deinen Ansatz habe ich nicht so ganz verstanden...
-
Also hier nochmal dasselbe, was mein Vorredner vorgeschlagen hat:
Wenn ich mich nicht ganz irre, werden die Einzelposten einfach addiert, allerdings gibt es leider auch "Spezialfälle".
Zunächst kannst du erstmal Zeichen für Zeichen prüfen, je nachdem, was es ist, addierst du eine Zahl drauf, also etwa so:
char Zahl [100]; cout << "Geben Sie die römische Zahl ein: "; cin << Zahl; int Dezimal = 0; for (int i = 0; i < strlen(Zahl); ++i) { switch (Zahl[i]) { case 'I': Dezimal += 1; break; case 'V': Dezimal += 5; break; case 'X': Dezimal += 10; break; case 'L': Dezimal += 50; break; case 'C': Dezimal += 100; break; /// usw... } }
Dieser Code übersieht aber, dass beispielsweise "IX" = 9 ist, und "IV" = 4. Also noch lange nicht optimal.
Das kommt aber, glaube ich, nicht allzu häufig vor. Wenn du es schaffst, diese Spezialfälle rauszufiltern, könnte es gehen.
-
Wow danke für die schnelle antwort.
das schlimme ist, ich hab meinen ansatz auch nicht verstanden.
ich dachte mir nur, wenn ein buchstabe eingegeben wird, dann interpretiert c ihn als die vorher deklarierte ziffer.
dein programm aber ist wundervoll, sind nur einige sachen drin von denen ich noch nichts gehört habe, aber ich hoffe das kommt nochint laenge = kette.size(); int zahl = 0; for(int i = 0; i < laenge; i++) switch((char) kette[i])
das ist mir zum beispiel schleierhaft
vielen dank
-
Matar schrieb:
int laenge = kette.size(); //ermitteln der laenge der eingegebenen kette int zahl = 0; //wird ja später ausgegeben for(int i = 0; i < laenge; i++) //solange die variable i kleiner ist als die laenge der kette soll er die variable i um 1 erhöhen switch((char) kette[i]) //wenn i < als laenge, dann soll er prüfen, was für ein zeichen an der i-ten stelle von der kette ist( [] ist der indexoperator) (der cast (char) kann weg.... das ist überflüssig)
das ist mir zum beispiel schleierhaft
vielen dank
nun gehe ich aber erstmal "das fünfte element" gucken..... wenn du weitere fragen hast, dann gucke ich sie mir später an.... hast du das problem des programms schon gefunden?
-
Danke nochmal euch beiden.
@leech problem gefunden, durch vorredner
doch ich hab kein prinzip im kopf das alles auszuschliessen, man könnte die spezialfälle mit if deklarieren, aber das wäre sehr vielalso danke nochmal, ich schau jetzt auch auch das element.
-
Mach es zum Beispiel so:
for (int i = 0; i < strlen(Zahl); ++i) { switch (Zahl[i]) { case 'I': if (Zahl[i+1] == 'V') Dezimal -= 1; else Dezimal += 1; break; } }
Dieser Code behandelt den Spezialfall "IV": Denn mit dem Code oben würde er "6" ausgeben. Hier prüft er, ob das nächste Zeichen eine V ist und zieht schonmal 1 ab, denn danach addiert er ja 5 dazu.
Ähnlich musst du es auch bei den weiteren Spezialfällen tun (IX, und alles was 10 bzw. 100 weniger ist als eine Zahl usw.).
-
Ich hab sowas mal für die bash geschrieben, sollte relativ einfach nach C++ umsetzbar sein. Der Code fängt allerdings keine ungültigen Eingaben ab; das war mir zu aufwändig.
#! /bin/bash function valueOfChar() { case "$1" in 'M'|'m') echo 1000;; 'D'|'d') echo 500;; 'C'|'c') echo 100;; 'L'|'l') echo 50;; 'X'|'x') echo 10;; 'V'|'v') echo 5;; 'I'|'i') echo 1;; *) echo -1;; esac } function convertToArab() { ROMNR="$1" ROMNR_LEN="${#ROMNR}" INDEX=0 ARABNR=0 while [ "$INDEX" -lt "$ROMNR_LEN" ] do CUR_VAL=$(valueOfChar ${ROMNR:$INDEX:1}) NEXT_VAL=$(valueOfChar ${ROMNR:$((INDEX + 1)):1}) if [ "$CUR_VAL" -eq "-1" ]; then echo "$ROMNR" ist keine römische Zahl return elif [ "$CUR_VAL" -ge "$NEXT_VAL" ];then ARABNR=$((ARABNR + CUR_VAL)) else ARABNR=$((ARABNR - CUR_VAL)) fi INDEX=$((INDEX + 1)) done echo $ARABNR } until [ -z "$1" ] do echo $(convertToArab "$1") shift done
Arabische in römische Zahlen zu wandeln, ist ungleich einfacher - der entsprechende Code sah so aus:
#!/bin/bash function convertToRoman() { ROM_NUM_ARRAY=(1000 900 500 400 100 90 50 40 10 9 5 4 1) ROM_LETTER_ARRAY=(M CM D CD C XC L XL X IX V IV I) if [ "$1" -le "0" ] || [ "$1" -ge "4000" ] ; then echo $1 kann nicht als römische Zahl dargestellt werden. else ARABNR=$1 ROMNR="" INDEX=0 while [ "$ARABNR" -gt "0" ] do while [ "$ARABNR" -ge ${ROM_NUM_ARRAY[${INDEX}]} ] do ARABNR="$((ARABNR - ROM_NUM_ARRAY[INDEX]))" ROMNR=${ROMNR}${ROM_LETTER_ARRAY[${INDEX}]} done INDEX="$((INDEX + 1))" done echo $ROMNR fi } until [ -z "$1" ] do echo $(convertToRoman $1) shift done
-
man könnte ja vielleicht die ziffern in ein enum packen...
also:
I = 0
V = 1
X = 2
L = 3
usw...dann prüft halt switch, was der momentane eintrag ist...
wenn es das dann ermittelt hat, kann es durch if prüfen, ob die nächste ziffer "größer" ist als die momentane... wenn das zutrifft, dann wird die momentane zahl abgezogen, ansonsten hinzuaddiert... das wäre nun mein vorschlag.... was meinen die anderen dazu?
-
Ja, eine gute Idee, müsste gehen. Das mit der enum scheint auch noch einer der besseren Wege zu sein, den Vergleich dann ordentlich hinzubringen.
Also im Code wohl so:
enum Ziffern { I = 1, V = 5, X = 10, L = 50, C = 100, M = 1000, Ende, }; ... int Dezimal = 0; Ziffern AktuelleZiffer, NaechsteZiffer; for (i = 0; i < strlen(Zahl); ++i) { switch (Zahl[i]) { case 'I': AktuelleZiffer = I; break; // usw. .... } switch (Zahl[i + 1]) { case 'I': NaechsteZiffer = I; break; // usw. .... } if (NaechsteZiffer > AktuelleZiffer) Dezimal -= (int) AktuelleZiffer; else Dezimal += (int) AktuelleZiffer; }
Ich weiß nicht, ob eventuell doch noch ein Denkfehler bezüglich der Römischen Zahlen drin ist, aber eigentlich müsste das halbwegs passen.
-
ich glaube nicht, dass jetzt noch ein denkfehler drin ist.... Bsp.:
MCD = 1000 - 100 + 500 = 1400
MCC = 1000 + 100 + 100 = 1200@ Matar:
Haste alles verstanden? Wenn nicht, dann frag besser nochmal nach... kennst du ein enum (enumeration = aufzählung)? ist dir das prinzip dahinter klar? könntest du den sourcecode von JensE erklären?//edit
obwohl: was ist denn mit VIC? ich kenne mich nicht mehr sogut mit römischen Ziffern aus.. hatte ich in der 6. Klasse oder so...VIC = 5 - 1 + 100 = 104? //das würde ja nach dem programm rauskommen... aber stimmt das auch?
oder
VIC = 100 - 6 = 94?
-
moinsen
ich denke mal ich kann das theoretisch nachvollziehen. ich muss das neue wissen jetzt nur oft genug für mich selbst anwenden und in all möglichen operationen austesten, learning by doing
nochmals vielen lieben dank für eure mühen, da werd ich euch bald sicher wieder mit was neuem nerven
-
ein problem gab es doch noch! Wenn man nur eine Ziffer eingegeben hat, dann war der Wert NEGATIV! also: I == -1
und falsche eingaben wurden nicht abgefangen.... hier ist mal der code von mir...#include <iostream> using namespace std; int main() { string kette; cout << "Bitte geben Sie eine Kette bestehend aus roemischen Zahlen ein: "; cin >> kette; int Dezimal = 0; enum Ziffern { Ende = 0, I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000}; Ziffern AktuelleZiffer, NaechsteZiffer; for(int i = 0; i < kette.size(); i++) { switch (kette[i]) { case 'I': AktuelleZiffer = I; break; case 'V': AktuelleZiffer = V; break; case 'X': AktuelleZiffer = X; break; case 'L': AktuelleZiffer = L; break; case 'C': AktuelleZiffer = C; break; case 'D': AktuelleZiffer = D; break; case 'M': AktuelleZiffer = M; break; default: cout << "Keine gueltige Eingabe!" << endl; cin.get();cin.get(); return 0; } switch (kette[i + 1]) { case 'I': NaechsteZiffer = I; break; case 'V': NaechsteZiffer = V; break; case 'X': NaechsteZiffer = X; break; case 'L': NaechsteZiffer = L; break; case 'C': NaechsteZiffer = C; break; case 'D': NaechsteZiffer = D; break; case 'M': NaechsteZiffer = M; break; default: NaechsteZiffer = Ende; break; } if (NaechsteZiffer > AktuelleZiffer) Dezimal -= (int) AktuelleZiffer; else Dezimal += (int) AktuelleZiffer; } cout << "Diese Zahl ist: " << Dezimal << endl; cin.get(); cin.get(); return 0; }
ist doch eigentlich ganz einfach, gelle?
und es macht nichts, wenn man hier im forum nach fragt, wenn man mal nicht weiterkommt... man muss aber zuerst selber mal nachgedacht haben und seine vorüberlegungen zeigen, damit die anderen wissen, ob man was selber gemacht hat oder ob die für einen nur die HA machen sollen... dieses ist KEIN HA FORUM!
-
auch wenn das kein HA forum ist klau ich mir einfach mal deinen code
1. sieht der übersichtlicher aus als meine idee und
2. funktioniert der auchalso mein dank gebührt euch, die ihr mir fleissig eure hilfe angeboten habt.
bis zum nächsten komplettausfall von mir... dürfte nicht alzulange dauern ( C is irgendwie schon schwer )
-
Ich will ja nicht eure Arbeit nieder machen, aber versucht mal mit eurem Quellcode XIC (nur mal als Beispiel) auszurechnen.
Ich habe mir mal erlaubt, auch noch dieses Manko zu beheben und direkt mal den Quellcode ein wenig durch zu dokumentieren, damit er etwas verständlicher ist. Das Resultat...
#include <iostream> #include <string> using namespace std; int main() { //Variablen deklarieren. string latin; int arabic = 0; int positionOfBiggestNumeral; int currentPosition; enum numerals { I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000 }; numerals currentNumeral; //Römische Zahl abfragen. cout << "Geben Sie eine r\x94mische Zahl ein." << endl; cin >> latin; //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"); } //Jede Ziffer der römischen Zahl durchgehen. for (currentPosition = 0; currentPosition < latin.size(); 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 falscher Eingabe cout << "Die eingegebene Ziffer ist ung\x81ltig." << endl; //Fehlermeldung aus, wartet system("PAUSE"); //bestätigung ab und beendet return 0; //das Programm frühzeitig. } //Arabische Zahl dem Kontext entsprechend um den Wert der //aktuellen Ziffer dekrementieren oder inkrementieren. if (currentPosition >= positionOfBiggestNumeral) { arabic += currentNumeral; } else { arabic -= currentNumeral; } } //Arabische Zahl ausgeben. cout << "Die arabische Zahl lautet: " << arabic << endl; //Betätigung abwarten und Programm beenden. system("PAUSE"); return 0; }
-
leech schrieb:
//edit
obwohl: was ist denn mit VIC? ich kenne mich nicht mehr sogut mit römischen Ziffern aus.. hatte ich in der 6. Klasse oder so...VIC = 5 - 1 + 100 = 104? //das würde ja nach dem programm rauskommen... aber stimmt das auch?
oder
VIC = 100 - 6 = 94?ich hatte das problem ja schon mal weiter oben angesprochen.... nun haben wir ja aber den richtigen code... der auch richtig funktioniert...
-
Soweit ich weiß, gilt diese Abzugsregel nur für einzelne (römische) Ziffern, z.B. IV, IX oder CM. Sowas wie VIC oder XIM wäre dann ungültig.
-
dein programm ist leider nicht richtig...
http://www.mathematische-basteleien.de/roemisch.htm
wenn man die römische ziffer CMXLVIII bei deinem programm eingibt, dann kommt 968 heraus... laut der seite soll aber 948 herauskommen...
bei meinem programm stimmt es aber... also ist dein programm nicht richtig...
-
leech schrieb:
ich glaube nicht, dass jetzt noch ein denkfehler drin ist.... Bsp.:
MCD = 1000 - 100 + 500 = 1400
MCC = 1000 + 100 + 100 = 1200also da ist aber ein denkfehler drin. MCD ist nicht 1000 - 100 + 500, sondern 1000 + (500 - 100).
leech schrieb:
VIC = 5 - 1 + 100 = 104? //das würde ja nach dem programm rauskommen... aber stimmt das auch?
oder
VIC = 100 - 6 = 94?beides ist falsch. VIC gibts nich, 104 entspräche CIV. 94 schreibt man als XCIV, iirc, weil VIC- wie du schön demonstrierst- mehrdeutig ist.
-
das hat mich ja auch verunsichert, da man 2 werte herausbekommen konnte...
scrub schrieb:
also da ist aber ein denkfehler drin. MCD ist nicht 1000 - 100 + 500, sondern 1000 + (500 - 100).
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
@Schrankwand:
Noch ei Bsp.:http://www.matheboard.de/lexikon/R�mische_Ziffern,definition.htm#Darstellung
MCMLXXXIV == 1984 bei dir kommt 2186 heraus... irgendwo musst du da wohl einen fehler drin haben...