Berechnung römischer zahlen in ganze zahlen



  • 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 auch

    also 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.



  • @Schrankwand:

    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 = 1200

    also 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...



  • 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.


Anmelden zum Antworten