quadratische Gleichung in einer Zeile einlesen



  • So, ich habs hinbekommen.

    while ( !(fEingabe==4))																
    	{
    		printf ("\nGeben sie die Gleichung bitte in der Form a*x^2+b*x+c=d ein\n\n");	
    		gets(szEingabe);																
    		fEingabe = sscanf (szEingabe,"%f*x^2+%f*x+%f=%f", &fa, &fb, &fc, &fd);			
    	}
    

    So funktionierts ganz gut. Ich habe noch keinen Fall gefunden in dem Schwachsinn produziert wird.
    Vielen Dank an euch Beide!



  • Wenn Dein Prof. Euch gesagt hat, dass Ihr mit sscanf arbeiten sollt, dann passt das schon. Besonders gutes C++ ist das nicht und sscanf ist nicht typsicher. Wenn das in der Vorlesung vorkam, dann gib es so ab, aber behalte bitte im Hinterkopf, dass Du es anders machen wirst, wenn Du irgendwann mal richtiges C++ programmierst.



  • Walli schrieb:

    Besonders gutes C++ ist das nicht und sscanf ist nicht typsicher.

    Das gilt natürlich ebenso für die anderen C-Funktionen wie printf() und gets() .



  • Das liegt dann wohl daran, daß das C++ ist; im Gegensatz zu deinem Code, der in C geschrieben ist.

    Ich hab das bis jetzt gedanklich immer in einen Pott geworfen und den Unterschied ignoriert. Ich hab noch mal nachgeschaut, wir werden wohl ausschließlich C behandeln.



  • Die Aufgabe an sich - mit dem Einlesen der quadratischen Gleichung - finde ich ziemlich schwierig für einen Anfänger. Wenn man das Problem verallgemeinert, und fordert, ein beliebiges Polynom einzulesen, bei dem die einzelnen Summanden in beliebiger Reihenfolge und auch mehrfach mit der gleichen Potenz in x auftreten dürfen, dann ist dies jenseits von allem, was man einem Anfänger zumuten kann.

    Andererseits ist es erstaunlich, was man mit boost.spirit relativ schnell und mit wenig Code zum Laufen bringt. Vorausgesetzt man kann auf dem Klavier spielen ...

    #include <boost/spirit/include/classic_core.hpp>
    #include <boost/bind.hpp>
    #include <boost/scoped_ptr.hpp>
    #include <iostream>
    #include <vector>
    #include <string>
    
    namespace spirit = boost::spirit::classic;
    
    template< typename InIter >
    struct polynom_grammer : public spirit::grammar< polynom_grammer< InIter > >
    {
        struct Koeff
        {
            Koeff() : m_value(1.0), m_sign(1), m_power_of_x(0) {}
            double m_value;
            int m_sign;
            int m_power_of_x;
        };
    
        template< typename ScannerT >
        struct definition
        {
            spirit::rule< ScannerT >  power_of_x, plus_minus, expr, r;
            int const eins, minus_eins;
            definition( polynom_grammer const& self )
                : eins( 1 ) // Bem.: notwendig, da assign_a(i,j) auch bei j eine Referenz speichert
                , minus_eins( -1 )
            {
                using boost::bind;
                using namespace spirit;
                power_of_x = ch_p('x')[assign_a( self.m_cur->m_power_of_x, eins )]  // x[^Exponent]
                >> !( '^' >> uint_p[assign_a( self.m_cur->m_power_of_x )] );
                plus_minus = '+' | ch_p('-')[assign_a( self.m_cur->m_sign, minus_eins )];   // + oder -
                expr = 
                    ( 
                    ( real_p[assign_a( self.m_cur->m_value )] >> !( !ch_p('*') >> power_of_x ) ) // Koeffizient [[*]power_of_x]
                    |   ( !plus_minus >> power_of_x )   // oder [plus_minus] power_of_x
                    )[bind( &polynom_grammer::store, &self, _1, _2 )];
                r = expr >> *( plus_minus >> expr );    // Ausdrücke mit +- verketten
            } 
            spirit::rule< ScannerT > const& start() const { return r; }
        };
    
        explicit polynom_grammer( std::vector< double >& poly )
            : m_polynom( poly )
            , m_cur( new Koeff ) 
        {}
    
        void store( InIter, InIter ) const
        {
            assert( m_cur->m_power_of_x >= 0 );
            // --   aktuellen Koeffizienten *m_cur im Polynom abspeichern
            const std::size_t n = m_cur->m_power_of_x;
            if( m_polynom.size() <= n )
                m_polynom.resize( n + 1, 0.0 );
            m_polynom[ n ] += m_cur->m_sign * m_cur->m_value;
    
            *m_cur = Koeff();   // reset
        }
    
        std::vector< double >& m_polynom;
        boost::scoped_ptr< Koeff > m_cur;
    };
    
    int main()
    {
        using namespace std;
        cout << " --- ein Polynomparser " << endl;
        cout << "   Geben Sie z.B. '-x^2 + 3x -12' ein;" << endl;
        cout << "   anschliessend werden die Koeffizienten ausgegeben " << endl;
        cout << "   [q or Q] to quit\n" << endl;
    
        for( string str; getline( cin, str ); )
        {
            using namespace spirit;
            if (str.empty() || str[0] == 'q' || str[0] == 'Q')
                break;
    
            cout << "-------------------------\n";
            vector< double > polynom;
            polynom_grammer< string::iterator > g( polynom );
            if( parse( str.begin(), str.end(), g.use_parser<0>(), space_p ).full )
            {
                cout << "[" << str << "] parses OK: " << endl;
                copy( polynom.rbegin(), polynom.rend(), ostream_iterator< double >( cout << "Koeff: ", " " ) );
                cout << endl;
            }
            else
            {
                cout << "Parsing failed\n";
            }
            cout << "-------------------------\n" << endl;
        }
        return 0;
    }
    

    man erhält z.B. folgende Ausgabe:

    --- ein Polynomparser
       Geben Sie z.B. '-x^2 + 3x -12' ein;
       anschliessend werden die Koeffizienten ausgegeben
       [q or Q] to quit
    
    x-5
    -------------------------
    [x-5] parses OK:
    Koeff: 1 -5
    -------------------------
    
    8x^2+5*x
    -------------------------
    [8x^2+5*x] parses OK:
    Koeff: 8 5 0
    -------------------------
    
    -x + 34x^3 + 7
    -------------------------
    [-x + 34x^3 + 7] parses OK:
    Koeff: 34 0 -1 7
    -------------------------
    
    -x + 34*x^3 + 7 + 5x
    -------------------------
    [-x + 34*x^3 + 7 + 5x] parses OK:
    Koeff: 34 0 4 7
    -------------------------
    

    :xmas2: Werner



  • Werner Salomon schrieb:

    Andererseits ist es erstaunlich, was man mit boost.spirit relativ schnell und mit wenig Code zum Laufen bringt.

    Sieht jetzt weder nach relativ schnell noch nach wenig Code aus... Aber ich glaube es dir schon. 😉

    Ich lese mich gerade ein wenig in Boost.Regex ein, das ist ja sozusagen die Vorstufe von Boost.Spirit... Mal sehen 🙂



  • Werner Salomon schrieb:

    Die Aufgabe an sich - mit dem Einlesen der quadratischen Gleichung - finde ich ziemlich schwierig für einen Anfänger. Wenn man das Problem verallgemeinert, und fordert, ein beliebiges Polynom einzulesen, bei dem die einzelnen Summanden in beliebiger Reihenfolge und auch mehrfach mit der gleichen Potenz in x auftreten dürfen, dann ist dies jenseits von allem, was man einem Anfänger zumuten kann.

    Andererseits ist es erstaunlich, was man mit boost.spirit relativ schnell und mit wenig Code zum Laufen bringt. Vorausgesetzt man kann auf dem Klavier spielen ...

    Von dir hätte ich erwartet, dass du das nur mit stringstreams und << >> Operatorüberladung machst.



  • ich hätte die eingabe übrigens sehr viel einfacher gemacht:

    const size_t maxExponent = 2; //quadratische fkt halt ^^
    
    for (size_t i(maxExponent); i != 0; ++i)
    {
      std::cout << "Geben sie x^" << i << " ein:";
      std::cin >> ;//speichern halt
    }
    std::cout << "Geben sie das absolut-Glied ein";//ich hoffe, man nennt den faktor vor x^0 so ;D
    std::cin >> ;//speichern halt - könnte man auch mit in die schleife machen, aber würd ich nicht - weil x^0 hässlich aussieht und es dann mit der schleife ein wenig umständlicher werden würde ^^
    

    bb



  • unskilled schrieb:

    ich hätte die eingabe übrigens sehr viel einfacher gemacht:

    "Sehr viel einfacher" heißt in diesem Fall: nicht der Aufgabenstellung entsprechend. Die Eingabe sollte in EINER Zeile erfolgen.



  • otze schrieb:

    unskilled schrieb:

    ich hätte die eingabe übrigens sehr viel einfacher gemacht:

    "Sehr viel einfacher" heißt in diesem Fall: nicht der Aufgabenstellung entsprechend. Die Eingabe sollte in EINER Zeile erfolgen.

    oh verzeihung - das hatte ich überlesen ^^
    bb



  • Huhu,

    Ich habe ebenfalls eine ähnliche Aufgabe aufbekommen. Jedoch muss ich hierbei keine Quadratische Gleichung in einer Zeile einlesen, sondern die Pythagoras-Gleichung. Aber das Prinzip ist ja ähnlich ...

    Mit dem Systemrumpf, quasi die Fallunterscheidungen sowie die allgemeine Berechnung, habe ich keinerlei Probleme, aber ich wüsste nicht, wie ich die While-Schleife von Knotze am Anfang des Programmes integrieren sollte. Könntet ihr mir vielleicht dabei helfen?

    Ich habe zumindestens die Variablen angepasst, fEingabe durch int iEingabe = 0 am Anfang des Programms ersetzt, sowie char szEingabe[81] deklariert. Jedoch wüsste ich jetzt nicht, wie nur die While-Schleife zu dem Erfolg führen soll, dass die Gleichung von der Konsole in einer Zeile eingelesen wird, weil mir im Allgemeinen das Prinzip nicht ganz so klar ist, wieso man eine While-Schleife benutzt. Entweder führt mein Programm nun zum Absturz oder zu einer 1000-fachen Ausgabe der printf-Zeile.

    Ich würde mich über Ratschläge und Hilfen sehr freuen. Danke im Voraus.

    von Knotze
    
    while ( !(fEingabe==4))                                                               
        {
            printf ("\nGeben sie die Gleichung bitte in der Form a*x^2+b*x+c=d ein\n\n");   
            gets(szEingabe);                                                               
            fEingabe = sscanf (szEingabe,"%f*x^2+%f*x+%f=%f", &fa, &fb, &fc, &fd);           
        }
    

Anmelden zum Antworten