Mini Taschenrechner



  • Hallo zusammen,
    habe hier ein mini Rechner Programm aus dem Script( der falsch ist )
    habe die Folien weitergelesen in der Hoffnung es besser zu verstehen aber dieser code ist so von durcheinander , dass ich total verzweifelt bin .

    int main() try {
        int lval{ 0 };
        int rval{ 0 };
        char op{ ' ' };
        cout << "Rechenausdruck (mit +,-,*,/, Ende mit ;) "; // wie z.B. 2*3+4;
        cin >> lval;
        if (!cin) {
            cerr << "Kein linker Operand";
            return -1;
        }
        while (cin >> op && op != ';') {
            if (!cin) {
                cerr << "Kein Operator";
                return -2;
            }
            cin >> rval;
            if (!cin) {
                cerr << "Kein rechter Operand";
                return -3;
            }
            switch (op) {
            case '+':
                lval += rval;
                break;
            case '-':
                lval -= rval;
                break;
            case '*':
                lval *= rval;
                break;
            case '/':
                lval /= rval;
                break;
            default: {
                cerr << "Unbekannter Operator";
                return -4;
            }
            } //switch()
        } // while()
        cout << "Ergebnis: " << lval << endl;
        return 0;
    }
    


  • Hallo

    Was ist die Frage?

    LG

    EDIT: Das wäre IMO im C++-Forum besser aufgehoben.



  • Fytch schrieb:

    Hallo

    Was ist die Frage?

    LG

    Ich weiß nicht was hier genau mit linken und rechten operanten gemeint ist? 😕 🙄



  • Operanden sind die Parameter von Operationen. Im Ausdruck a+b ist a der linke Operand und b der rechte.



  • Hi Helenchen,

    ein bisschen mit http://format.krzaq.cc/ formatiert, Main eigene Klammern verpasst,

    int lval{ 0 };
        int rval{ 0 };
        char op{ ' ' };
    

    durch

    int lval ( 0 );
        int rval ( 0 );
        char op  ( ' ' );
    

    ersetzt

    int lval = 0;
        int rval = 0;
        char op  = ' ';
    

    wäre auch gegangen, und eine Funktion eingebaut die nach der Anzeige auf ein Enter wartet.
    Statt zweimal getline hätte man vorher die Eingabe auch flushen können, hab aber die Syntax dafür nicht im Kopf.

    Programm läuft, aber beachtet nicht die Punktrechnen geht vor Strichrechnen-Regel, aber das tun einfache Taschenrechner heute auch nciht mehr.

    #include <iostream>
    #include <string>
    #include <stdexcept>
    
    using namespace std;
    
    void warte()
    {
      string x;
      getline( cin, x );
      getline( cin, x );
    }
    
    int main()
    {
        string x;
        try
        {
            int lval ( 0 );
            int rval ( 0 );
            char op  ( ' ' );
            cout << "Rechenausdruck (mit +,-,*,/, Ende mit ;) "; // wie z.B. 2*3+4;
            cin >> lval;
            if (!cin)
            {
                cerr << "Kein linker Operand";
                warte();
                return -1;
            }
            while (cin >> op && op != ';')
            {
                if (!cin)
                {
                    cerr << "Kein Operator";
                    warte();
                    return -2;
                }
                cin >> rval;
                if (!cin)
                {
                    cerr << "Kein rechter Operand";
                    warte();
                    return -3;
                }
                switch (op)
                {
                    case '+':
                        lval += rval;
                        break;
                    case '-':
                        lval -= rval;
                        break;
                    case '*':
                        lval *= rval;
                        break;
                    case '/':
                        lval /= rval;
                        break;
                    default:
                    {
                        cerr << "Unbekannter Operator";
                        warte();
                        return -4;
                    }
                } // switch()
            } // while()
            cout << "Ergebnis: " << lval << endl;
    
            warte();
            return 0;
        }
        catch (const runtime_error& re)
        {
    
            cerr << "Fehler: " << re.what() << endl;
            warte();
            return -1;
        }
    }
    


  • Statt zweimal getline hätte man vorher die Eingabe auch flushen können, hab aber die Syntax dafür nicht im Kopf.

    Meinst du die cin.ignore()? 😃



  • Hi,

    hab mich auch mal an 'nem Taschenrechner versucht:

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <string>
    #include <string_view>
    #include <cctype>
    #include <stdexcept>
    
    template< typename T, typename U >
    bool contains( T const& container, U const& key ) {
    	using std::begin, std::end;
    	return std::find( begin( container ), end( container ), key ) != end( container );
    }
    struct leveler {
    	int depth = 0;
    	int operator()( char c = '\0' ) {
    		return depth += ( c == '(' ) - ( c == ')' );
    	}
    };
    bool is_balanced( std::string_view expr ) {
    	leveler l;
    	for( std::size_t i = 0; i < expr.size() && l( expr[ i ] ) > 0; ++i );
    	return !l();
    }
    double eval( std::string_view expr );
    bool match( double& val, char op, std::string_view expr, std::size_t i, double( *fun )( double, double ) ) {
    	return expr[ i ] == op && ( val = fun( eval( expr.substr( 0, i ) ), eval( expr.substr( i + 1 ) ) ), true );
    }
    double eval( std::string_view expr ) {
    	for( ; !expr.empty() && std::isblank( expr.front() ); expr.remove_prefix( 1 ) );
    	for( ; !expr.empty() && std::isblank( expr.back() ); expr.remove_suffix( 1 ) );
    	if( !is_balanced( expr ) )
    		throw std::runtime_error{ "imbalanced parentheses" };
    	for( std::string_view inner; expr.size() >= 2 && expr.front() == '(' && expr.back() == ')' && is_balanced( inner = expr.substr( 1, expr.size() - 2 ) ); expr = inner );
    	double result = 1;
    	leveler l;
    	for( std::size_t i = expr.size(); i--; )
    		if( !l( expr[ i ] ) && i && std::tolower( expr[ i - 1 ] ) != 'e' )
    			if( std::size_t prev = expr.substr( 0, i ).find_last_not_of( " \t" ); prev != std::string_view::npos && !contains( "+-*/%^", expr[ prev ] ) && (
    				match( result, '+', expr, i, []( double x, double y ){ return x + y; } ) ||
    				match( result, '-', expr, i, []( double x, double y ){ return x - y; } ) ) )
    				return result;
    	for( std::size_t i = expr.size(); i--; )
    		if( !l( expr[ i ] ) )
    			if( match( result, '*', expr, i, []( double x, double y ){ return x * y; } ) ||
    				match( result, '/', expr, i, []( double x, double y ){ return x / y; } ) ||
    				match( result, '%', expr, i, std::fmod ) )
    				return result;
    	for( std::size_t i = 0; i < expr.size(); ++i )
    		if( !l( expr[ i ] ) )
    			if( match( result, '^', expr, i, std::pow ) )
    				return result;
    	for( ; !expr.empty() && ( expr.front() == '+' || expr.front() == '-' && ( result *= -1 ) ); expr.remove_prefix( 1 ) );
    	if( expr.empty() )
    		throw std::runtime_error{ "expected expression" };
    	return result * ( expr.front() == '(' ? eval( expr ) : std::stod( std::string( expr ) ) );
    }
    int main() try {
    	for( std::string ln; std::getline( std::cin, ln ); std::cout << eval( ln ) << '\n' );
    } catch( std::exception const& e ) {
    	std::cerr << e.what() << '\n';
    	return -1;
    }
    

    LG



  • Hi Helenchen,

    helenchen schrieb:

    Statt zweimal getline hätte man vorher die Eingabe auch flushen können, hab aber die Syntax dafür nicht im Kopf.

    Meinst du die cin.ignore()? 😃

    Kann sein, muss man ausprobieren. 2 * getline geht aber auch. Das erste schließt die vorige Eingabe ab und das zweite wartet auf eine Entertasten-Betätigung.

    Grundregel für das gangbar machen von Quelltext:
    Immer zuerst mit http://format.krzaq.cc/ in Form bringen. Dabei den Style file benutzen. Dann sieht man schon, wo die Fehler sind.

    Wenn vom Programm Ergebnisse oder Fehler ausgegeben werden hinterher eine Warte-Funktion aufrufen, damit man die Ausgabe lesen kann bevor das Fenster geschlossen wird.

    Keine Intitalisirungen mit {0}. Einfache Variablen mit int Wert = 0; intialisieren, Bei Klassen und ähnlichen mit ( 0 ) initialisieren.

    die main-Funktion muss eigene Klammern haben. das try muss innerhalb der Klammern der Main-Funktion stehen.
    try kennzeichnet einen geschützten Bereich. Das braucht aber auch einen catch-Block, in dem eventuell auftretende Exceptions gefangen werden.

    Und wenn Du mit allem fertig bist noch mal mit http://format.krzaq.cc/ in Form bringen

    Gruß Mümmel



  • muemmel schrieb:

    Keine Intitalisirungen mit {0}. Einfache Variablen mit int Wert = 0; intialisieren, Bei Klassen und ähnlichen mit ( 0 ) initialisieren.

    Doch. Zumindest ist es vermessen, das als falsch oder schlecht darzustellen.
    Der Trend geht nun mal in die Richtung.



  • Hi Jockelx,

    Jockelx schrieb:

    muemmel schrieb:

    Keine Intitalisirungen mit {0}. Einfache Variablen mit int Wert = 0; intialisieren, Bei Klassen und ähnlichen mit ( 0 ) initialisieren.

    Doch. Zumindest ist es vermessen, das als falsch oder schlecht darzustellen.
    Der Trend geht nun mal in die Richtung.

    Nicht alles was ein Trend ist ist auch immer gleich gut.
    Bei einfachen Variablen bin ich nach wie vor der Überzeugung, dass
    x = 0;
    wesentlich übersichtlicher ist als
    x { 0 }
    und auch bei sonstigen Objekten sagen die Runden Klammern dem Auge, das da was übergeben wird, was bei geschweiften nicht so der Fall ist.

    Sicher, man kann es so machen, aber ausmeiner Sicht dient es nicht übermäßig der Übersichtlichkeit.
    Und für absolute Anfänger ist Übersichtlichkeit nun mal das A und O beim Programmieren.

    Gruß Mümmel



  • hier habe ich versucht ein bisschen die Ausgabe zu verbessern. mehre Rechenschritte berechnet er aber falsch.

    #include <iostream>
    #include <stdexcept>
    
    using namespace std;
    
    void warte()
    {
        string x;
    
        getline(cin, x);
        getline(cin, x);
    }
    int addiere(int a, int b)
    {
    
        int add = a + b;
        return add;
    }
    int substract(int a, int b)
    {
    
        int sub = a - b;
        return sub;
    }
    int multiply(int a, int b)
    {
    
        int mult = a * b;
        return mult;
    }
    int division(int a, int b)
    {
        int div = a / b;
        return div;
    }
    
    int main()
    {
    
        try {
    
            signed int lval{ 0 };
            signed int rval{ 0 };
            signed int result{ 0 };
            char op{ ' ' };
    
            cout << "Rechenausdruck (mit +,-,*,/, Ende mit ;) "; // wie z.B. 2*3+4;
            cin >> lval;
    
            if (!cin) {
                cerr << "Kein linker Operand" << endl;
                warte();
    
                return -1;
            }
            while (cin >> op && op != ';') {
                if (!cin) {
                    cerr << "Kein Operator";
                    warte();
    
                    return -2;
                }
    
                cin >> rval;
    
                if (!cin) {
                    cerr << "Kein rechter Operand";
                    warte();
    
                    return -3;
                }
    
                switch (op) {
    
                case '+':
                    cout << lval + rval << endl;
                    break;
                case '-':
                    cout << lval - rval << endl;
                    break;
                case '*':
                    cout << lval * rval << endl;
                    break;
                case '/':
                    cout << lval / rval << endl;
                    break;
                default: {
                    cerr << "Unbekannter Operator";
                    warte();
                    return -4;
                }
                } //switch()
            } // while()
    
            cout << "Ergebnis: " << result << endl;
            warte();
            return 0;
        }
        catch (const runtime_error& re) {
            cerr << "Fehler: " << re.what() << endl;
            warte();
            return -1;
        }
    }
    

    Wie mache ich :
    unäres Minus -- und unäres Plus ++ 😕
    PS: Die initialisierten linker und rechter Operant in {} wollte der Proff so haben, es geht nur mit C++11 Compiler 😉



  • Hi Helenchen,

    helenchen schrieb:

    hier habe ich versucht ein bisschen die Ausgabe zu verbessern. mehre Rechenschritte berechnet er aber falsch.

    Du hast den Code etwas kaputtoptimiert. 😉

    cout << lval - rval << endl;
      break;
    

    da wird nur ausgerechnet und an cout ausgegeben.
    Es basiert aber alles darauf, dass das vorige Ergebnis mitgeschleift wird und der nächste Rechenschritt darauf aufbaut.
    In der Originalversion erfolgt das dadurch, dass lval nur einmal am Start eingegeben wird, und dann immer das Ergebnis an lval zugewiesen wird.

    lval -= rval;
    // ausführlich geschrieben als lval = lwahl - rval;
      break;
    

    wenn Du jeweils das Zwischenergebnis ausgeben willst, kannst Du das auch gleich an cout schreiben, aber das macht nur Sinn, wenn Du dann auch gleich den Weg dahin ausgibst.

    cout << lval << ' '<< op << ' '  << rval " = ";
      lval -= rval;
      cout << lval << endl;
      break;
    

    Aber das kann optisch ziemlich durcheinander kommen, wenn Du bei der Eingabe zwischendurch die Entertaste drückst.

    Wie mache ich :
    unäres Minus -- und unäres Plus ++ 😕

    Wenn Du mit Leerzeichen eingibst geht das, wenn es einigermaßen passt geht es auch ohne. Die Eingabe ist da ziemlich clever und merkt, was eine Zahl mit Vorzeichen ist und was das nächste Rechenzeichen
    Alternativ müsstest Du zeichenweise von der Eingabe lesen und immer jeweils entscheiden, was das jeweilige Zeichen zu bedeuten hat und dann auch die ganzen Konvertierungen selbst vornehmen

    Warte geht mit ignore und getline an Stelle von 2 * getline:

    void warte()
    {
      string x;
      cin.ignore( );
      getline( cin, x );
    }
    

    Extra Rechenfunktionen müssen bei der simplen Rechnung nicht sein, aber wenn dann etwa so:

    int substract(int a, int b)
    {
        int sub = a - b;
        return sub;
    }
    // oder kürzer und eventuell effizienter (ermöglicht Returnwertoptimierung)
    int substract(int a, int b)
    {
        return a - b;
    }
    ...
    
      lval = substract( lwahl, rval );
      break;
    

    PS: Die initialisierten linker und rechter Operant in {} wollte der Proff so haben, es geht nur mit C++11 Compiler 😉

    Naja, des Profs Wille ist sein Himelreich. 🙄

    Gruß Mümmel

    PS: Hab jetzt erst mitbekommen, was Du mit den unären -- und ++ meinst. also nicht das Vorzeichen, sondern den Increment- und Decrement-Operator. Nun, die sind c++-Spezifisch und somit nicht möglich. Der Teschenrechner verarbeitet nur "normale Grundrechenarten". das ist meiner Meiung nach nur über eine komplett eigene Einzelzeichenauswertung machbar. Ich vermute mal, das sprengt den Rahmen was Du damit erreichen willst. Außerdem machen die auch keinen Sinn, weil sie erhöhen ja den Wert auf den sie sich beziehen. Erhöhen kann man aber nur eine Variable und keine Ziffer. ++3 macht ja auch in c++ keinen Sinn und ist soviel ich weis auch nicht zulässig, denn es würde ja bedeuten, dass du die 3 nach 4 umdefinierst.

    Gruß Mümmel



  • Muss als nächstes:

    erweiterte Grammatik implemenieren:
    Primary :
    Number
    '(' Expression ')'
    '-' Primary
    '+' Primary

    obwohl in der Aufgabe davor steht :
    Ein Rechenausdruck wie -7*3 soll auch so eingegeben werden können, und
    nicht wie bislang nur als (0-7)*3 akzeptiert werden.
    Obwohl : Primary ist :
    Number
    '(' Expression ')'
    Also Faktor
    Zahl
    Rechenausdruck in Klammern
    Solche Logik verwirrt mich ein wenig 😕 😃
    weißt jemand was der Proff will ? 🙄



  • helenchen schrieb:

    weißt jemand was der Proff will ? 🙄

    Die Aufgabe, die du gerade beschrieben hast?

    helenchen schrieb:

    Solche Logik verwirrt mich ein wenig 😕 😃

    Entschuldigung, falls das beleidigend 'rüberkommt, aber wenn dich diese einfache Logik verwirrt, dann wird das nichts mit dem Programmieren für dich. Wechsle am besten den Studiengang solange du noch kannst. Bei uns konnt' man in den ersten 2 Semestern in andere MINT-Fächer wechseln.



  • Hi Helenchen,

    helenchen schrieb:

    erweiterte Grammatik implemenieren:
    Primary :
    Number
    '(' Expression ')'
    '-' Primary
    '+' Primary
    Ein Rechenausdruck wie -7*3 soll auch so eingegeben werden können

    -7+3 kann auch mit der bisherigen Version so eingegeben werden. Auf meinem Computer rechnet der das richtig, weil das System schon selber erkennt, was alles zu einer Zahl gehört.

    Jetzt wird lediglich erwartet, das an Stelle einer direkten Zahl auch ein geklammerter Ausdruck stehen kann, der eine Zahl ergibt.
    Das vorhandene Programm ist dafür schon eine gute Grundlage, muss nur noch ein wenig überarbeitet werden.
    Die Berechnung kann nicht mehr direkt in Main erfolgen, sondern muss in einer extra Funktion Rechne erfolgen, die am Ende ihr Ergebnis zurück gibt.

    Main gibt nur in einem geschützten Block die Eingabeaufforderung aus, ruft Rechne auf und gibt anschließend das von Rechne gelieferte Ergebnis auf cin aus. Anschließend folgt nur noch der catch-Bock um Fehler abzufangen.

    In Rechne wird zuerst lval ermittelt und dann in einer Endlosschleife jeweils der Operator und danach wenn der Operator nicht ';' und nicht ')' ist rval ermittelt und rval entsprechend dem Operator auf lval angewendet.
    Ist der Operator ';' oder ')' dann wird ohne weitere Rechnung mit
    return lval;
    zurückgesprungen.

    Die beiden Operanden lval und rval kannst Du nicht mehr direkt einlesen, sondern must eine Funktion GetOperand erstellen. Die muss zuerst das 1. Zeichen des Operanden einlesen.
    Wenn es eine öffnende Klammer '(' ist, ruft sie Rechne auf und gibt deren Ergebnis zurück.
    Ist das eingelesene kein '(', dann muss das Zeichen mit unget (oder eventuell pushback) in die Eingabe zurückgestellt werden und danach ganz normal der nächste Zahlen-Wert von cin gelesen und zurückgegeben werden.
    Mehr ist aus meine Sicht nicht erforderlich.

    Gruß Mümmel



  • muemmel schrieb:

    Hi Helenchen,

    Ist das eingelesene kein '(', dann muss das Zeichen mit unget (oder eventuell pushback) in die Eingabe zurückgestellt werden.

    Gruß Mümmel

    wie funktioniert das mit unget bzw push_back ...cin.unget(op)? 🙄
    habe es mit putback() gemacht ,weil push_back bei mir nicht akzeptiert wurde.

    Hier ist mein Code, es funktioniert aber total falsch.

    #include <iostream>
    #include <stdexcept>
    
    using namespace std;
    
    void warte()
    {
        string x;
    
        cin.ignore();
        getline(cin, x);
        getline(cin, x);
    }
    int addiere(int a, int b)
    {
    
        int add = a + b;
        return add;
    }
    int substract(int a, int b)
    {
    
        unsigned int sub = a - b;
        return sub;
    }
    int multiply(int a, int b)
    {
    
        int mult = a * b;
        return mult;
    }
    int division(int a, int b)
    {
        int div = a / b;
        return div;
    }
    
    int rechne(signed int lval, signed rval)
    {
        char op{ ' ' };
        // signed int lval{0};
        //signed int rval{0};
        signed int result = lval;
        while (cin >> op && op != ';', ')') {
            switch (op) {
    
            case '+':
                result = addiere(lval, rval);
                break;
            case '-':
                result = substract(lval, rval);
                break;
            case '*':
                result = multiply(lval, rval);
                break;
            case '/':
                result = division(lval, rval);
                break;
            }
        }
        return result;
    }
    
    char getOperand(char op)
    {
        cin >> op;
        if (op == '(') {
            rechne;
        }
        else {
        }
        cin.putback(op);
    }
    int main()
    {
    
        string x;
        try {
    
            cout << "Rechenausdruck (mit +,-,*,/, Ende mit ;) " << endl; // wie z.B. 2*3+4;
    
            cout << "Ergebnis: " << rechne << endl;
            warte();
    
            return 0;
        }
    
        catch (const runtime_error& re) {
            cerr << "Fehler: " << re.what() << endl;
            warte();
            return -1;
        }
    }
    


  • Hi Helenchen,

    Du hast so ziemlich alles falsch gemacht und nichts beachet, was ich geschrieben habe.
    Gehen wir der Reihe nach durch.

    warte:
    hier reicht ignore und 1 getline

    Addire, subtrct...:
    die Funktionen sind eigentlich überflüssig
    die alte Version mit
    lval -= rval;
    war kürzer und besser

    getoperand:
    getoperand hat keine Parameterm sondern locale variablen int operand und char operator.
    wenn der eingelesene operator = '(' ist wird rechne() zurückgegeben
    ansonsten wird operator mit unget() zurückgestellt, Operand von cin eingelesen und zurückgegeben
    Getoperand ist vom typ int

    rechne:
    rechne hat keine parameter sondern die (bei Dir) auskommentierten variablen lval und rval.
    Zuerst wird rval mit
    rval = getoperator();
    eingelesen.
    Dann kommt eine Endlosschleife
    while ( 1 )
    oder
    for (;;)

    in der Schleife wird zuerst op von cin eingelesen

    dann wird über die switch-Anweisung op ausgewertet.
    wenn op = ')' oder op = ';' dann wird lval zurückgegeben

    bei +,-,/,* wird das ergebnis der jeweiligen funktion an lval gegeben.
    zB.

    rval =getoperator();
    lval = addiere( lval, rval );
    break;

    oder kürzer und besser

    rval =getoperator();
    lval += rval;
    break;

    So, Helenchen, nun versuchs noch mal.

    Gruß Mümmel



  • bei mir funktioniert getoperator nicht wenn ich schreibe:

    case '+': rval = getoperator(); lval += rval ;  break;
    

    auch wenn ich es vordefiniere 😞



  • Hi Helenchen,

    helenchen schrieb:

    bei mir funktioniert getoperator nicht wenn ich schreibe:

    case '+': rval = getoperator(); lval += rval ;  break;
    

    auch wenn ich es vordefiniere 😞

    und wie sieht getoperator bei Dir aus?

    Gruß Mümmel



  • Hi Helenchen,

    Wie sieht Dein gesamter Quelltext jetzt aus?

    Gruß Mümmel


Log in to reply