c++ Schulprojekt zum Thema Taschenrechner



  • schriftlich müsse es ja so gehen....

    z.B:

    293293092
    + 2345114
    295638206

    nur hab ich keine Ahnung wie ich das in c++ darstellen soll und kann da ich ja mit char arbeiten muss. Könntet ihr mir mal den Sourcecode dazu aufschreiben=



  • das sind deine hausaufgaben, die musst du selber koennen.
    wir helfen nur. fertigen code gibts aber nicht.

    weisst du denn, wie man die elemente eines arrays veraendert?



  • is nich meine Hausaufgabe,....
    is nur einfacher zu erklären wenn ich was vor mir sehe. Bin für jede Hilfe dankbar da meine Note davon abhängt. Da mein Vertretungslehrer der Oberspassti is und mir NULL hilft bin ich nun hier auf der Suche nach Rat.

    > ka wie man Elemente innerhalb eines Array's verändert(haben wir glaub ich noch gar nicht gemacht)



  • Mal als Ansatzpunkt ein einzelner Addierschritt:

    i1=zahl[0][p1]-'0';
    i2=zahl[1][p2]-'0';
    sum=i1+i2+uebertrag;
    zahl[2][paus]=sum%10;
    uebertrag=sum/10;
    

    PS: Ein Array wird übrigens von 0 an gezählt, also schriebst du mit "cin>>zahl[2];" außerhalb deines eigenen Speichers - und außerdem sollte man für String-Eingaben nicht den op>> verwenden.



  • CStoll schrieb:

    Mal als Ansatzpunkt ein einzelner Addierschritt:

    i1=zahl[0][p1]-'0';
    i2=zahl[1][p2]-'0';
    sum=i1+i2+uebertrag;
    zahl[2][paus]=sum%10;
    uebertrag=sum/10;
    

    PS: Ein Array wird übrigens von 0 an gezählt, also schriebst du mit "cin>>zahl[2];" außerhalb deines eigenen Speichers - und außerdem sollte man für String-Eingaben nicht den op>> verwenden.

    Kannst du mir mal die Schritte genauer erklären? Also in dieser Zeile wird mit "dem und dem Befehle, dass bezweckt"...?
    wenn ich den op gets(string) verwende wird dieser 2 mal OHNE for-schleife in der Eingabe wiederholt und ermöglicht keine Eingabe 😕

    void eingabe(void)
    {
      cout << "Bitte geben Sie hier Ihre 1. Zahl ein: ";
      gets(zahl[0]);
      cout << "Bitte geben Sie hier Ihre 2. Zahl ein: ";
      gets(zahl[0]);
      return;
     }
    


  • das problem mit der doppelten Eingabeaufforderung hat sich erledigt,....
    ich hatte im "MAIN" Programm noch eingabe(); stehen,..deswegen hat sich dieses wiederholt.



  • OK, dann Schritt für Schritt:

    //bestimme den Wert der aktuellen Ziffer von zahl[0] (erster Summand)
    i1=zahl[0][p1]-'0';
    //das selbe bei zahl[1] (zweiter Summand)
    i2=zahl[1][p2]-'0';
    //eigentliche Summierung (mit Übertrag aus voriger Stelle)
    sum=i1+i2+uebertrag;
    //schreibe die Summenziffer nach zahl[2] (Ergebnis)
    zahl[2][paus]=sum%10+'0';//sorry, da war oben ein kleiner Fehler
    //bestimme nötigen Übertrag für die nächste Stelle
    uebertrag=sum/10;
    

    Das ganze mußt du jetzt in eine Schleife verpacken, die p1, p2 und paus (Positionen des aktuellen Summierungsschrittes) richtig vom Stringende (=Einer) zum Anfang runterzählt.

    PS: Natürlich benötigst du zusätzlich zu den Operanden noch etwas Speicher für das Rechenergebnis (und bei der Multiplikation kann das etwas länger als 20 Stellen werden)

    PPS: Ist dir übrigens aufgefallen, daß du beide Operanden in den selben Bereich einliest?

    PPPS: gets ist übrigens genauso unsicher in Bezug auf die Eingabelänge wie >>. Nimm lieber cin.get(buffer,len).



  • Es gibt die sogenannte 'umgekehrte polnische Notation'. Die hat den Vorteil, dass man relativ leicht einen Taschenrechner programmieren kann, der damit funktioniert.
    Zunächst würde ich mal das Problem aufteilen. Erstens hat man einen Taschenrechner und zweitens soll der mit Zahlen rechnen, die nicht in int's oder double passen und als char-Sequenz dargestellt werden sollen.

    Bei so einem Taschenrechner mit umgekehrter polnischer Notation braucht man nur zwei Dinge. Entweder wird eine Zahl (Operand) auf einen Stack abgelegt oder es wird eine Operation aufgerufen, die auf dem Stack arbeitet; In einer Hauptschleife wird der Input-Stream mitgegeben, von dem Operanden und Operationen gelesen werden

    template< typename T > // T ist der Typ der Zahl; das Problem kommt später
    class Taschenrechner
    {
    public:
        explicit Taschenrechner( std::ostream& out ) // Ausgabe-Stream mitgeben
            : m_out( out )  // Referenz auf Ausgabe-Stream merken
            , m_numbers()   // das ist der Stack; hier noch leer
        {}
    
        void work( std::istream& in ) // Hauptschleife
        {
            for(;;) // verlassen via 'return' s.u.
            {
                std::string val;  // da wir nicht wissen was kommt, erstmal Text lesen
                in >> val;
                if( val == "x" )
                    return;
                if( is_operand( val ) )  // Ist das ein Operand (zahl)?
                    push( operand( val ) ); // dann auf den Stack damit
                else if( is_operator( val ) )  // ein Operator?
                {
                    calc( val[0] ); // dann Aktion ausführen
                    display(); // und (Zwischen-)Ergebnis anzeigen
                }
                else
                    std::cerr << "?? " << val << std::endl;
            }
        }
    

    Dann braucht man - wie schon oben erwähnt - zunächst die 'Haupt-'Methoden push (Zahl auf Stack) und calc (Operation auf Zahlen auf Stack ausführen)

    void push( const T& operand )
        {
            m_numbers.push( operand ); // klar; was sonst
        }
    
        void calc( char operator_ )
        {
            switch( operator_ ) // hier wird immer eine binäre Operation aufgerufen .. 
            {
            case '+': binary_op( std::plus< T >() ); break;  // Funktor für +
            case '-': binary_op( std::minus< T >() ); break; // Funktor für -; usw.
            case '*': binary_op( std::multiplies< T >() ); break;
            case '/': binary_op( std::divides< T >() ); break;
            default:
                std::cerr << "unbekannter operator: '" << operator_ << "'" << std::endl;
                return;
            }
        }
    

    Die Binäre Operation wirkt auf die letzten beiden Operanden im Stack und legt das Ergebnis wieder im Stack ab.

    private:
        template< typename Op >
        void binary_op( Op op )
        {
            if( m_numbers.empty() )
                return; // wenn nix da, gleich raus
            const T param2 = m_numbers.top();
            m_numbers.pop();
            if( m_numbers.empty() ) // prüfen ob 2.Parameter vorhanden
            {
                m_numbers.push( param2 );
                return;
            }
            m_numbers.top() = op( m_numbers.top(), param2 ); // <-- hier passiert's
        }
    

    Das ganze ist als Template realisiert. Der Template-Parameter ist ein Funktor mit 2 Parametern; binär halt.

    So jetzt fehlen noch eine paar Hilfsmethoden is_operand, operand, is_operator und display.

    // wie prüft man, ob eine Zahl, deren Typ man nicht kennt, das richtige Format hat?
        static bool is_operand( const std::string& val )
        {
            std::stringstream buf( val );
            T x;
            return !(buf >> x).fail(); // gucken, ob einlesen gut geht
        }
        static T operand( const std::string& val )
        {
            std::stringstream buf( val );
            T x;
            buf >> x;
            return x;
        }
    
        static bool is_operator( const std::string& val )
        {
            return val == "+" || val == "-" || val == "*" || val == "/";
        }
    
        void display()
        {
            if( !m_numbers.empty() )
                m_out << m_numbers.top() << std::endl;
        }
    

    und die Member von Taschenrechner<> natürlich. Da bleibt nur der Stack und der Ausgabe-Stream

    // --   Members
        std::ostream& m_out;
        std::stack< T > m_numbers;
    };  // Taschenrechner<> Ende
    

    Benötigte Includes (oben drüber natürlich)

    #include <iostream>
    #include <functional>   // plus, multiplies, usw.
    #include <stack>
    #include <string>
    #include <sstream>
    

    Damit lässt sich bereits ein Taschenrechner erstellen:

    #include "Taschenrechner.h"
    #include <iostream>
    
    int main()
    {
        using namespace std;
        cout << "Taschenrechner (umgekehrte polnische Notation)" << endl;
        Taschenrechner< double > tr( cout );
        tr.work( cin );
        return 0;
    }
    

    Mal starten und eingeben 3(206)5+2\frac{3*(20-6)}{5+2} bzw. in umgekehrter polnischer Notation (..und immer Zwischenraum lassen!)

    3 20 6 - * 5 2 + /
    

    ergibt als Ergebnis 6 🕶

    Zahlen mit mehr als 11 oder 12 Stellen sind so nicht möglich. Dazu muss man den 'double' im main() gegen eine Klasse Zahl austauscht.

    #include "Taschenrechner.h"
    #include "Zahl.h"
    #include <iostream>
    
    int main()
    {
        using namespace std;
        cout << "Taschenrechner (umgekehrte polnische Notation)" << endl;
        Taschenrechner< Zahl > tr( cout );
        tr.work( cin );
        return 0;
    }
    

    In zahl.h sieht's ungefähr so aus:

    #include <iosfwd>
    #include <deque>
    
    class Zahl
    {
    public:
        Zahl()
            : m_ziffern( 1, '0' )
        {}
    
        // --   für den Taschenrechner
        friend Zahl operator+( const Zahl& a, const Zahl& b );
        friend Zahl operator-( const Zahl& a, const Zahl& b );
        friend Zahl operator*( const Zahl& a, const Zahl& b );
        friend Zahl operator/( const Zahl& a, const Zahl& b );
    
        friend std::istream& operator>>( std::istream& in, Zahl& zahl );
        friend std::ostream& operator<<( std::ostream& out, const Zahl& zahl );
    
    private:
        std::deque< char > m_ziffern;
    };
    

    noch ohne Vorzeichen und ohne Hilfsroutinen. Jetzt kann man sich einem Problem nach dem anderen zuwenden.
    1.) operator+:

    Zahl operator+( const Zahl& a, const Zahl& b )
    {
        std::deque< char > erg;
        int carry = 0;
        std::deque< char >::const_iterator i1 = a.m_ziffern.begin();
        std::deque< char >::const_iterator i2 = b.m_ziffern.begin();
        while( i1 != a.m_ziffern.end() || i2 != b.m_ziffern.end() || carry > 0 )
        {
            const int sum = 
                  ((i1 != a.m_ziffern.end()) ? int(*i1++) - int('0'): 0) 
                + ((i2 != b.m_ziffern.end()) ? int(*i2++) - int('0'): 0)
                + carry;
            erg.push_back( char(sum % 10) + '0' );
            carry = sum / 10;
        }
        return Zahl( true, erg );
    }
    

    .. bei den anderen Methoden dürfen sich andere mal probieren 😃 . Die Division kommt mir richtig schwierig vor 🕶

    Ich bin mir dessen bewußt, dass das nicht der Code für "blutige Anfänger" ist 🙄 ; aber vielleicht hilft es trotzdem. Es ist ja auch mal ein Anlass sich z.B. die Hilfe zu std::plus<> oder so genau anzusehen.

    Gruß
    Werner



  • CStoll schrieb:

    //bestimme den Wert der aktuellen Ziffer von zahl[0] (erster Summand)
    i1=zahl[0][p1]-'0';
    //das selbe bei zahl[1] (zweiter Summand)
    i2=zahl[1][p2]-'0';
    //eigentliche Summierung (mit Übertrag aus voriger Stelle)
    sum=i1+i2+uebertrag;
    //schreibe die Summenziffer nach zahl[2] (Ergebnis)
    zahl[2][paus]=sum%10+'0';//sorry, da war oben ein kleiner Fehler
    //bestimme nötigen Übertrag für die nächste Stelle
    uebertrag=sum/10;
    

    1.) CStoll, du bist ne maschine 😃 kein mensch *gg*
    2.) Was bringt dir dieses -'0' ? wird dann automatisch nach int gecastet?

    // Ok 2. hat sich geklärt, da ja '0' der 48te wert in der ASCII table ist, und dann abgezogen ergibt das die zahl usw is klar 😃

    MFG
    Schinken



  • Schinken schrieb:

    1.) CStoll, du bist ne maschine 😃 kein mensch *gg*

    *guckt an sich runter* Bis gestern war ich mir noch sicher, ein Mensch zu ein 😃

    2.) Was bringt dir dieses -'0' ? wird dann automatisch nach int gecastet?

    // Ok 2. hat sich geklärt, da ja '0' der 48te wert in der ASCII table ist, und dann abgezogen ergibt das die zahl usw is klar 😃

    Gut erkannt - genauer wandelt der Ausdruck c-'0' die Ziffernzeichen '0' bis '9' in die zugehörigen Zahlenwerte 0 bis 9 um 😉


Anmelden zum Antworten