Mit dem Ergebnis weiterechnen



  • Hallo zusammen,

    meine Aufgabe ist es einen kleinen Taschenrechner zu programmieren. Ich bin so weit gekommen das, das Programm eine einfache Addition, Subtraktion usw. durchführen kann. Ich habe es auch geschafft nach Ausgabe das Ergebnis des Programmes von vorne zu beginnen.
    Ich möchte jetzt aber das Programm so verändern, dass ich mit dem Ergebnis weiterrechnen kann oder eine neue Rechnung zu starten. Leider bekommen ich es aber nicht hin das mein Programm mit dem Ergebnis der ersten Rechnung die zweite Rechnung beginnt.

    Ich hoffe jemand, von euch kann mir dabei helfen. Leider bin ich noch sehr unerfahren was C++ betrifft.

    #include <iostream>                                       
    #include <cmath>											
    using namespace std;
    
    int main()
    {
    	float zahl1;
    	float zahl2;
    	float ergebnis;
    	string rechenzeichen;
    	string again;
    	bool run = true;
    	
    	while(run == true)
    	{
    	 
    		cout<< "              Erste  Zahl  : "<<endl;
    		cin >>                      zahl1;
    		cout<< "              Rechenzeichen: ";
    		cin >>                rechenzeichen;
    		cout<< "              Zweite Zahl  : "<<endl;
    		cin >>                       zahl2;
    	
    		if(rechenzeichen == "+")
    		{
    		ergebnis = zahl1 + zahl2;
    		}
    	
    		if(rechenzeichen == "-")
    		{
    		ergebnis = zahl1 - zahl2;
    		}
    	
    		if(rechenzeichen == "*")
    		{
    		ergebnis = zahl1 * zahl2;
    		}
    	
    		if(rechenzeichen == "/")
    		{
    		ergebnis = zahl1 / zahl2;
    		}
    	
    		cout<< "Ergenis der Berechnung beträgt"<< endl;
    		cout<< ergebnis <<endl;
    		cout<< "Nochmal rechnen? (y/n)";
    		cin >> again;
    		if(again == "y")
    		{
    			run = true;
    			ergebnis = zahl1;
    		}
    		else
    		{
    			run = false;
    		}
    	
    	}
    	
    	return 0;
    }```cpp
    
    


  • Was bezweckts du mit Zeile 38?


  • Gesperrt

    Im Prinzip so: zahl1 = ergebnis; goto zeile6;
    zuvor noch das Label "zeile6:" vor die Zeile 6 setzen.

    Ich weiß allerdings nicht, ob es die goto-Anweisung in C++ noch gibt. Mir war so, als sollte sie rausfliegen. Die Profis hassen goto!



  • @RBS2 sagte in Mit dem Ergebnis weiterechnen:

    goto zeile6;

    goto statt den Kopf der while-Schleife einfach ein paar Zeilen runter zu verschieben ... Ja ne, ist klar. Yes no, is clear. 👍🏻

    @Becksprinz Würdest Du bitte deinen Beitrag bearbeiten, Deinen Code markieren und auf das lustige </> neben dem Dropdown mit "C++" klicken? Danke.

    @Becksprinz sagte in Mit dem Ergebnis weiterechnen:

    Ich möchte jetzt aber das Programm so verändern, dass ich mit dem Ergebnis weiterrechnen kann oder eine neue Rechnung zu starten.

    Mit anderen Worten dein zahl1 soll beim nächsten Schleifendurchlauf den Wert von ergebnis haben und nicht nochmal vom Benutzer eingegeben werden. Stell' dazu die Aufforderung zum eingeben und das Einlesen von zahl1 vor die Schleife.

    BTW solltest Du Deine Variablen dort definieren, wo sie benötigt werden (so nah als möglich) und nicht alle an einem Funktionsanfang hinklatschen (nur weil es in C im Jahre Schnee noch nicht anders ging).

    ... und wie @DirkB schon gesagt hat, da ist was kehrvehrt.

    else if statt else beim check auf den Operator wär wohl auch noch angebracht und das Denglisch gemisch bei den Bezeichnern muss auch nicht sein. Vor der Division solltest Du auch noch sicherstellen, daß der Divisor nicht 0 ist.

    Aja, und <string> fehlt. Dafür ist <cmath> überflüssig.

    Geschmacksmuster:

    #include <limits>
    #include <string>
    #include <iostream>
    
    void clear(std::istream &is)
    {
    	is.clear();  // clear flags
    	// and discard everything left in the stream up to and including a newline:
    	is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    
    int main()
    {
    	double lhs;  // left hand side
    	while (std::cout << "Erste  Zahl: ", !(std::cin >> lhs)) {
    		std::cerr << "Eingabefehler.\n\n";
    		clear(std::cin);  // get rid of garbage left in the stream
    	}
    
    	// for-loop to not clutter the surrounding scope with the loop variable
    	for (std::string again; again != "n";) {
    		std::string op;
    		while (std::cout << "Operator: ", !(std::cin >> op)) {
    			std::cerr << "Eingabefehler.\n\n";
    			clear(std::cin);
    		}
    
    		double rhs;  // right hand side
    		while (std::cout << "Zweite Zahl: ", !(std::cin >> rhs)) {
    			std::cerr << "Eingabefehler.\n\n";
    			clear(std::cin);
    		}
    
    		if (op == "+") {
    			lhs += rhs;   // lhs += rhs; instead result = lhs + rhs;
    		}                 // to use the result as lhs for the next iteration.
    		else if (op == "-") {
    			lhs -= rhs;
    		}
    		else if (op == "*") {
    			lhs *= rhs;
    		}
    		else if (op == "/") {
    			if (rhs == 0.) {
    				std::cerr << "Division durch 0 ist gaga.\n\n";
    				continue;
    			}
    			lhs /= rhs;
    		}
    		else {
    			std::cerr << "Ungueltiger Operator.\nZweite Zahl wird ignoriert.\n\n";
    			continue;
    		}
    
    		std::cout << "Ergenis der Berechnung beträgt " << lhs;
    	
    		while (std::cout << "\n\nNochmal rechnen? (j/n) ", !(std::cin >> again) ||
    			   again != "j" && again != "n")
    		{
    			std::cerr << "Eingabefehler";
    			clear(std::cin);
    		}
    	}
    
    	// when control reaches the end of main() without return statement
    	// the effect is the same as "return 0;"
    }
    

    `

    Untested. NO WARRANTY. 😉



  • Ich hätte in diesem Fall nicht nur 'clear()' ausgelagert, sondern die komplette while-Schleife zur Eingabe, die vier Mal wiederholt wird.

    Bei Benutzereingaben in der Konsole kann man sich nahezu unendlich verkünsteln, ist aber für Anfänger oft nicht sinnvoll, man weiß einfach wie die Eingabe auszusehen hat und hält sich dementsprechend daran. Natürlich ist es schön, solides Error-Handling zu haben, das Mindeste wäre m. E. nach, dass man keine Endlosschleife produzieren kann.

    Darf man fragen weshalb std::string für Operator und again, obwohl diese wie chars verwendet werden?



  • @HarteWare sagte in Mit dem Ergebnis weiterechnen:

    Ich hätte in diesem Fall nicht nur 'clear()' ausgelagert, sondern die komplette while-Schleife zur Eingabe, die vier Mal wiederholt wird.

    Special, extra n00b unfriendly Version nur für dich:

    #include <limits>
    #include <vector>
    #include <string>
    #include <iostream>
    #include <exception>
    #include <algorithm>
    #include <functional>
    
    void clear(std::istream &is)
    {
    	is.clear();
    	is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    
    template<typename T>
    T read(std::istream &is, char const *prompt = {}, char const *error = {}, std::vector<T> const valid = {})
    {
    	T value;
    	while ((prompt && std::cout << prompt), !(is >> value) || !valid.empty() &&
    	       std::find(valid.cbegin(), valid.cend(), value) == valid.cend())
    	{
    		error && (std::cerr << error);
    		clear(is);
    	}
    	return value;
    }
    
    int main()
    {
    	auto const *error_msg{ "Eingabefehler\n\n" };
    	auto lhs{ read<double>(std::cin, "Erste Zahl: ", error_msg) };
    
    	for (std::string again; again != "n";
    		 again = read<std::string>(std::cin, "Nochmal rechnen? (j/n) ", error_msg, { "j", "n" }))
    	{
    		std::vector<std::string> const valid_ops{ "+", "-", "*", "/" };
    		auto op{ read<std::string>(std::cin, "Operator: ", error_msg, valid_ops) };
    		auto rhs{ read<double>(std::cin, "Zweite Zahl: ", error_msg) };
    
    		try {
    			std::function<void()> operators[] {
    				[&]() { lhs += rhs; },
    				[&]() { lhs -= rhs; },
    				[&]() { lhs *= rhs; },
    				[&]() { if (rhs == 0.)
    				            throw std::invalid_argument{ "Division durch 0 ist gaga.\n\n" };
    				        lhs /= rhs; }
    			};
    
    			operators[std::find(valid_ops.cbegin(), valid_ops.cend(), op) - valid_ops.cbegin()]();
    		}
    		catch (std::invalid_argument &e) {
    			std::cerr << e.what();
    			continue;
    		}
    
    		std::cout << "Ergenis der Berechnung betraegt " << lhs << ".\n\n";
    	}
    }
    

    @HarteWare sagte in Mit dem Ergebnis weiterechnen:

    Darf man fragen weshalb std::string für Operator und again, obwohl diese wie chars verwendet werden?

    Weil man sich so das umständliche Leeren des Streams spart wenn der in einen char extrahierte Wert zwar ok ist aber danach Müll kommt (zumindest wenn der Müll kein whitespace enthält).



  • Der Code ist nun fast komplett verändert, mein Vorschlag war lediglich zusätzlich die while-Schleife auszulagern, ohne einen Zuwachs an Komplexität (abgesehen von einem template-Parameter). Die Kunst liegt darin, im richtigen Maße zu generalisieren. Als Beispiel: die Funktion könnte readFromCin heißen und der istream Parameter wegfallen. Diese Art von Interaktion macht weniger Sinn, wenn man beispielsweise aus einer Datei ließt.

    Du musst Dich nicht genötigt fühlen, für mich den perfekten Code zu schreiben, ich hatte gehofft ich tue einen Gefallen, wenn ich meine Meinung zum vorgestellten Code teile.

    Die Komplexität wäre in diesem Fall besser dahin gelenkt, dass man einen kleinen recursive-descent-parser daraus macht, damit der Taschenrechner auch tatsächlich nützlich wird. Das wäre ein gutes aber noch überschaubares Projekt, falls der TE dieses Thema weiterführen möchte.



  • @HarteWare sagte in Mit dem Ergebnis weiterechnen:

    mein Vorschlag war lediglich zusätzlich die while-Schleife auszulagern

    Ja, schon. Nur sind die dinger nicht 4 x gleich.

    @HarteWare sagte in Mit dem Ergebnis weiterechnen:

    einen kleinen recursive-descent-parser daraus macht

    ➡

    @Becksprinz sagte in Mit dem Ergebnis weiterechnen:

    Leider bekommen ich es aber nicht hin das mein Programm mit dem Ergebnis der ersten Rechnung die zweite Rechnung beginnt.

    😖



  • Morgen zusammen,

    vielen Dank für die schnelle Hilfe. @Swordfish Danke für den Code. Ich habe ihn ausprobiert und er funktioniert auch. Ich glaube, wenn ich den Code meiner Klasse vorstelle, werden die schnell merken, dass ich ihn nicht selber erstellt habe 😳 . Leider ist das noch nicht unser Level in der Klasse, auf dem wir programmieren.

    Wie du gesagt hast, habe ich die zahl1 vor die Schleife gesetzt. Leider rechnet das Programm im zweiten Durchgang dann immer noch mit dem wert der zahl1 und setzt nicht das ergebnis=zahl1. Weiß jemand wo es noch hängt?

    #include <iostream>                                          
    #include <cmath>											
    using namespace std;
    
    int main()
    {
    	float zahl1;
    	float zahl2;
    	float ergebnis;
    	string rechenzeichen;
    	string again;
    	bool run = true;
    	
    		cout<< "              Erste  Zahl  : "<<endl;
    		cin >>                      zahl1;
    	
    	while(run == true)
    	{
    	 
    		
    		cout<< "              Rechenzeichen: ";
    		cin >>                rechenzeichen;
    		cout<< "              Zweite Zahl  : "<<endl;
    		cin >>                       zahl2;
    	
    		if(rechenzeichen == "+")
    		{
    		ergebnis = zahl1 + zahl2;
    		}
    	
    		if(rechenzeichen == "-")
    		{
    		ergebnis = zahl1 - zahl2;
    		}
    	
    		if(rechenzeichen == "*")
    		{
    		ergebnis = zahl1 * zahl2;
    		}
    	
    		if(rechenzeichen == "/")
    		{
    		ergebnis = zahl1 / zahl2;
    		}
    	
    		cout<< "Ergenis der Berechnung betraegt"<< endl;
    		cout<< ergebnis <<endl;
    		cout<< "Nochmal rechnen? (j/n)";
    		cin >> again;
    		if(again == "j")
    		{
    			run = true;
    			ergebnis = zahl1;
    		}
    		else
    		{
    			run = false;
    		}
    	
    	}
    	
    	return 0;
    }
    


  • @Becksprinz sagte in Mit dem Ergebnis weiterechnen:

    Leider rechnet das Programm im zweiten Durchgang dann immer noch mit dem wert der zahl1 und setzt nicht das ergebnis=zahl1. Weiß jemand wo es noch hängt?

    @Swordfish sagte in Mit dem Ergebnis weiterechnen:

    ... und wie @DirkB schon gesagt hat, da ist was kehrvehrt.

    @DirkB sagte in Mit dem Ergebnis weiterechnen:

    Was bezweckts du mit Zeile 38?

    @Becksprinz sagte in Mit dem Ergebnis weiterechnen:

     ergebnis = zahl1;  // war mal Zeile 38
    

    Nach dieser Zeile hat ergebnis den gleichen Wert wie zahl1, nicht umgekehrt.

    Wie du in meinem Code sehen kannst könntest du dir ergebnis auch sparen und das Ergebnis der Operation direkt in zahl1 ablegen.



  • Hallo zusammen,

    das mit dem kehrvehrt habe ich jetzt auch verstanden. Sry das ich es erst so spät verstanden habe 😅 Kann mir jemand erklären, warum zahl1=ergebnis richtig ist und nicht ergebnis = zahl1🤔 ? Ich würde gerne mein Fehler verstehen, um es in Zukunft besser zu machen.

    Als Nächstes habe ich mich um die Division durch Null gekümmert(Zeile 58) oder zumindest versucht. Wenn ich dividiere und zahl2 =0 macht das Programm was es soll. Wenn ich aber a für addieren eingebe, dann führt das Programm trotzdem wieder die Division aus. Vor dem Ergänzen der Befehle um durch Null zu teilen hat das Programm noch funktioniert. Weis jemand woran es klemmt?

    #include <iostream>                                          
    #include <cmath>											
    
    using namespace std;
    
    int main()
    {
    	float zahl1;
    	float zahl2;
    	float ergebnis;
    	string rechenzeichen;
    	string again;
    	bool run = true;
    	system ("color f1");
    	
    	while(run == true)
    	{
    		cout<<endl;
    		cout<< "Erste Zahl"<<endl;
    		cin >> zahl1;
    		cout<<endl;
    		
    		while(run == true)
    		{
    			cout<< " Bitte geben Sie ein Rechenzeichen ein: "<<endl;
    			cout<<endl;
    			cout<< " Fuer Addition ein       [a] eingeben" <<endl; 
    			cout<< " Fuer Subtraktion ein    [s] eingeben"<<endl; 
    			cout<< " Fuer Multiplikation ein [m] eingeben"<<endl; 
    			cout<< " Fuer Division ein       [d] eingeben"<<endl;
    			cout<<endl; 
    			cin >>                rechenzeichen;
    			cout<<endl;
    			
    			
    			
    			
    			cout<< "              Zweite Zahl  : "<<endl;
    			cin >>                       zahl2;
    			cout<<endl;
    				
    	
    			if(rechenzeichen == "a")
    			{
    				ergebnis = zahl1 + zahl2;
    			}
    	
    			if(rechenzeichen == "s")
    			{
    				ergebnis = zahl1 - zahl2;
    			}
    	
    			if(rechenzeichen == "m")
    			{
    				ergebnis = zahl1 * zahl2;
    			}
    	
    			if((rechenzeichen == "d") && (zahl2 == 0))
    			{
    			
    				cout<< "Die Division durch Null ist nicht mathematisch definiert."<<endl;
    				continue;
    				
    			}
    			else
    			{
    				ergebnis = zahl1 / zahl2;
    				
    			}
    			
    	
    			cout<< "Ergenis der Berechnung betraegt"<< endl;
    			cout<< ergebnis <<endl;
    			cout<< "Mit Ergebnis weiterrechnen? (j/n)"<<endl;
    			cin >> again;
    			if(again == "j")
    			{
    				run = true;
    				zahl1 = ergebnis;
    			}
    			else
    			{
    				run = false;
    			}
    		}
    		cout<<"Eine neue Rechnung beginnen? (j/n)"<<endl;
    		cin >> again;
    		if(again == "j")
    		{
    			run = true;
    		}
    		else
    		{
    			run = false;
    		}
    	}
    }
    


  • @Becksprinz sagte in Mit dem Ergebnis weiterechnen:

    Kann mir jemand erklären, warum zahl1=ergebnis richtig ist und nicht ergebnis = zahl1 ? Ich würde gerne mein Fehler verstehen, um es in Zukunft besser zu machen.

    Weil das in C so definiert ist, dass das Ziel links vom = steht.
    (ist in der Mathematik ja auch meist so: y = f(x) )

    Die Bedingung if((rechenzeichen == "d") && (zahl2 == 0)) ist auch unwahr für "a". Also wird der else-Zweig ausgeführt.

    Du solltest den Vergleich auf 0 mit in den Divisonszweig nehmen.
    Besser noch, du machst ein switch oder eine if else if ...


Anmelden zum Antworten