<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Fakultät in Taschenrechner implementieren]]></title><description><![CDATA[<p>Hallo,</p>
<p>ich bin bei der Programmierung eines Taschenrechners, der +-*/ kann (aus dem Buch von Stroustrup) und möchte nun die Fakultät implementieren. Meine Fakultätsfunktion lautet:</p>
<pre><code>double fak (double val) //berechnet rekursiv die Fakultät einer Zahl
				  // rekursiv: Die Funktion ruft sich selbst auf
{
	if (val &gt; 1) 
	{
		return fak(val-1) * val;
    }
	else
		return 1;
}
</code></pre>
<p>Das der double-Typ nicht gut gewählt ist, weiß ich. Ich würd's gern erst zum Funktionieren bringen, bevor ich mir darüber Gedanken mache.</p>
<p>Das Programm läuft nach der Grammatik:</p>
<p><em>Ausdruck:</em><br />
Term<br />
Ausdruck &quot;+&quot; Term<br />
Ausdruck &quot;-&quot; Term<br />
<em>Term:</em><br />
Faktor<br />
Term &quot;*&quot;Faktor<br />
Term &quot;/&quot; Faktor<br />
<em>Faktor:</em> (-&gt; primary() )<br />
Zahl<br />
Ausdruck &quot;!&quot;<br />
&quot;(&quot; Ausdruck &quot;)&quot;<br />
<em>Zahl:</em><br />
Gleitkomma</p>
<p>Der Taschenrechner an sich ist ziemlich lang und ich will euch nicht unbedingt mit Code zu müllen. Daher hier nur der Abschnitt, in dem ich die Fakultät unterbringen will. Vielleicht hat jemand auch mal das Buch bearbeitet und kann sich erinnern, wie es ging.</p>
<pre><code>double primary()
{
    Token t = ts.get();

    switch (t.kind) {
	case '{': 
		 {    
            double d = expression();
            t = ts.get();
			if (t.kind != '}') error(&quot;'}' expected&quot;);
            return d;
        }
    case '(':    // behandle'(' Ausdruck ')'
        {    
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error(&quot;')' expected&quot;);
            return d;
        }
    case '8':     // wir verwenden '8' zur Repräsentation einer Zahl
		{
			double a = t.value;
			t = ts.get();
			if(t.kind == '!')
				return fak(a); //liefere die Fakultät der Zahl zurück
			else
				return a;  // liefere den Wert der Zahl zurück
		}
    default:
        error(&quot;Faktor erwartet&quot;);
    }
}
</code></pre>
<p>Es wird ein Token erzeugt, das eine Kategorie und einen Zahlenwert speichert. Für Zahlen wird als Kategorie '8' gewählt (willkürlich) und der Zahlenwert abgelegt. Für die Rechenoperationen wird nur die Kategorie (+-*/!) gespeichert.</p>
<p>Mein Problem:<br />
Das Token liefert mir einen Zahlenwert, ich bin also bei</p>
<pre><code>case '8':
</code></pre>
<p>An der Stelle müsste ich doch jetzt gucken, was dahinter steht, und wenn's ein '!' ist, dann die fak() aufrufen.</p>
<p>Sofern ich nur die Fakultät berechnen will, funktioniert das auch, allerdings geht sonst nichts mehr. Hat jemand eine Idee?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/311046/fakultät-in-taschenrechner-implementieren</link><generator>RSS for Node</generator><lastBuildDate>Tue, 04 Aug 2026 00:32:13 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/311046.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 25 Nov 2012 18:16:21 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Sun, 25 Nov 2012 18:16:21 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>ich bin bei der Programmierung eines Taschenrechners, der +-*/ kann (aus dem Buch von Stroustrup) und möchte nun die Fakultät implementieren. Meine Fakultätsfunktion lautet:</p>
<pre><code>double fak (double val) //berechnet rekursiv die Fakultät einer Zahl
				  // rekursiv: Die Funktion ruft sich selbst auf
{
	if (val &gt; 1) 
	{
		return fak(val-1) * val;
    }
	else
		return 1;
}
</code></pre>
<p>Das der double-Typ nicht gut gewählt ist, weiß ich. Ich würd's gern erst zum Funktionieren bringen, bevor ich mir darüber Gedanken mache.</p>
<p>Das Programm läuft nach der Grammatik:</p>
<p><em>Ausdruck:</em><br />
Term<br />
Ausdruck &quot;+&quot; Term<br />
Ausdruck &quot;-&quot; Term<br />
<em>Term:</em><br />
Faktor<br />
Term &quot;*&quot;Faktor<br />
Term &quot;/&quot; Faktor<br />
<em>Faktor:</em> (-&gt; primary() )<br />
Zahl<br />
Ausdruck &quot;!&quot;<br />
&quot;(&quot; Ausdruck &quot;)&quot;<br />
<em>Zahl:</em><br />
Gleitkomma</p>
<p>Der Taschenrechner an sich ist ziemlich lang und ich will euch nicht unbedingt mit Code zu müllen. Daher hier nur der Abschnitt, in dem ich die Fakultät unterbringen will. Vielleicht hat jemand auch mal das Buch bearbeitet und kann sich erinnern, wie es ging.</p>
<pre><code>double primary()
{
    Token t = ts.get();

    switch (t.kind) {
	case '{': 
		 {    
            double d = expression();
            t = ts.get();
			if (t.kind != '}') error(&quot;'}' expected&quot;);
            return d;
        }
    case '(':    // behandle'(' Ausdruck ')'
        {    
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error(&quot;')' expected&quot;);
            return d;
        }
    case '8':     // wir verwenden '8' zur Repräsentation einer Zahl
		{
			double a = t.value;
			t = ts.get();
			if(t.kind == '!')
				return fak(a); //liefere die Fakultät der Zahl zurück
			else
				return a;  // liefere den Wert der Zahl zurück
		}
    default:
        error(&quot;Faktor erwartet&quot;);
    }
}
</code></pre>
<p>Es wird ein Token erzeugt, das eine Kategorie und einen Zahlenwert speichert. Für Zahlen wird als Kategorie '8' gewählt (willkürlich) und der Zahlenwert abgelegt. Für die Rechenoperationen wird nur die Kategorie (+-*/!) gespeichert.</p>
<p>Mein Problem:<br />
Das Token liefert mir einen Zahlenwert, ich bin also bei</p>
<pre><code>case '8':
</code></pre>
<p>An der Stelle müsste ich doch jetzt gucken, was dahinter steht, und wenn's ein '!' ist, dann die fak() aufrufen.</p>
<p>Sofern ich nur die Fakultät berechnen will, funktioniert das auch, allerdings geht sonst nichts mehr. Hat jemand eine Idee?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274574</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274574</guid><dc:creator><![CDATA[Lieschen Müller]]></dc:creator><pubDate>Sun, 25 Nov 2012 18:16:21 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Sun, 25 Nov 2012 20:52:54 GMT]]></title><description><![CDATA[<p>Ich vermute, dass das, was ich gelesen habe, so ähnlich war. Ich denke aber, dass du die Fakultät nicht in dieser Funktion unterbringen kannst/solltest. Du hast doch bestimmt noch Funktionen für Plus/Minus und Mal/Geteilt. So eine müsstest du noch für die Fakultät erstellen. Könntest du mal mehr Code liefern?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274616</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274616</guid><dc:creator><![CDATA[wxSkip]]></dc:creator><pubDate>Sun, 25 Nov 2012 20:52:54 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Sun, 25 Nov 2012 22:43:33 GMT]]></title><description><![CDATA[<p>&quot;Ausdruck !&quot; dürfte nicht die richtige Regel sein -- 2 + 3! bedeutet nicht (2 + 3)!. Was du eigentlich haben willst, ist &quot;Faktor !&quot; (damit ginge dann auch n!!). Das Problem ist natürlich, dass diese Regel linksrekursiv wäre, was in einem Recdesc-Parser stumpf nicht geht.</p>
<p>Da du nicht vorher entscheiden kannst, ob der Ausdruck, den du gerade parst, eine Fakultät ist oder nicht, wirst du es hinterher tun müssen. Eine Möglichkeit wäre einen LL-freundliche Zwischenregel, etwa</p>
<p>Fakultät := Faktor &quot;!&quot;*</p>
<p>Umzusetzen beispielsweise als</p>
<pre><code class="language-cpp">double factorial()
{
    double n = primary(); // Hier rekursiv weiter zu primary

    Token t;

    while((t = ts.get()).kind == '!') {
        n = fak(n);
    }

    ts.putback(t);

    return n;
}
</code></pre>
<p>...und dann überall factorial() zu benutzen, wo vorher primary() stand.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274646</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274646</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Sun, 25 Nov 2012 22:43:33 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Mon, 26 Nov 2012 17:59:27 GMT]]></title><description><![CDATA[<p>Das stimmt, eigentlich will ich &quot;Faktor !&quot;.</p>
<p>Deine Variante finde ich sehr gut, wäre aber von allein nie darauf gekommen.</p>
<p>Noch zwei Fragen: Wieso ist das linksrekursiv? Was ist ein Recdesc-Parser?</p>
<p>Da wxSkip danach gefragt, hier noch etwas mehr Code, falls es noch interessant ist (seldons Vorschlag ist noch nicht eingearbeitet):</p>
<pre><code>class Token {
public:
    char kind;        // welche Kategorie von Token
    double value;     // für Zahlen: ein Wert  
    Token(char ch)    // erstelle ein Token aus einem char
        :kind(ch), value(0) { }    
    Token(char ch, double val)     // erstelle ein Token aus einem char und einem double
        :kind(ch), value(val) { }
};

//------------------------------------------------------------------------------

class Token_stream {
public:
   Token_stream();        // erstelle einen Token_stream, der aus cin liest 
   Token get();           // lies ein Token ein (get() ist anderswo definiert)
   void putback(Token t); // lege ein Token zurück 
private:
   bool full;    // befindet sich ein Token im Puffer?
   Token buffer; // hier legen wir ein Token ab, das mit putback() 
                 // zurückgestellt wurde
};

//------------------------------------------------------------------------------

// Der Konstruktor setzt full auf false, um anzuzeigen, dass der Puffer leer ist:
Token_stream::Token_stream()
:full(false), buffer(0)    // kein Token im Puffer
{
}

//------------------------------------------------------------------------------

// Die Memberfunktion putback() stellt ihr Argument zurück in den Puffer von Token_stream:
void Token_stream::putback(Token t)
{
    if (full) error(&quot;putback(): Zurueckstellen nicht moeglich, Puffer voll&quot;);
    buffer = t;       // kopiere t in den Puffer
    full = true;      // Puffer ist jetzt voll
}

//------------------------------------------------------------------------------

Token Token_stream::get()
{
    if (full) {       // gibt es bereits ein fertiges Token?
        // Token aus dem Puffer entfernen
        full=false;
        return buffer;
    } 

    char ch;
    cin &gt;&gt; ch;    // beachten Sie, dass &gt;&gt; Whitespace-Zeichen wie 
                  // Leerzeichen, Zeilenumbruch, Tabulatorzeichen, etc. überspringt

    switch (ch) {
    case ';':    // für &quot;Ausgeben&quot;
    case 'q':    // für &quot;Verlassen&quot;
	case '(': case ')': case '+': case '-': case '*': case '/': case '{': case '}': case '!':
        return Token(ch);        // jedes Zeichen repräsentiert sich selbst 
    case '.':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '9':
        {    
            cin.putback(ch);         // lege die Ziffer zurück in den Eingabestream
            double val;
            cin &gt;&gt; val;              // lies eine Gleitkommazahl 
            return Token('8',val);   // '8' repräsentiert &quot;eine Zahl&quot;
        }
    default:
        error(&quot;Ungueltiges Token&quot;);
    }
}

//------------------------------------------------------------------------------

double fak (double val) //berechnet rekursiv die Fakultät einer Zahl
				  // rekursiv: Die Funktion ruft sich selbst auf
{
	if (val &gt; 1) 
	{
		return fak(val-1) * val;
    }
	else
		return 1;
}

//------------------------------------------------------------------------------

Token_stream ts;        // stellt get() und putback() zur Verfügung  

//------------------------------------------------------------------------------

double expression();    // Deklaration, damit primary() expression() aufrufen kann

//------------------------------------------------------------------------------

// behandelt Zahlen und Klammern 
double primary()
{
    Token t = ts.get();
	//Token t2 = ts.get();

    switch (t.kind) {
	case '{': 
		 {    
            double d = expression();
            t = ts.get();
			if (t.kind != '}') error(&quot;'}' expected&quot;);
            return d;
        }
    case '(':    // behandle'(' Ausdruck ')'
        {    
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error(&quot;')' expected&quot;);
            return d;
        }
	case '8':     // wir verwenden '8' zur Repräsentation einer Zahl
		/*{
			double a = t.value;
			t = ts.get();
			if(t.kind == '!')
				return fak(a);
			else
				return a;  // liefere den Wert der Zahl zurück
		}*/
		return t.value;
    default:
        error(&quot;Faktor erwartet&quot;);
    }
}

//------------------------------------------------------------------------------

// behandelt *, / 
double term()
{
    double left = primary();
    Token t = ts.get();        // lies das nächste Token aus dem Token-Stream ein

    while(true) {
        switch (t.kind) {
        case '*':
            left *= primary();
            t = ts.get();
			break;
        case '/':
            {    
                double d = primary();
                if (d == 0) error(&quot;Division durch null&quot;);
                left /= d; 
                t = ts.get();
                break;
            }
		default: 
            ts.putback(t);     // stelle t wieder zurück in den Token-Stream
            return left;
        }
    }
}

//------------------------------------------------------------------------------

// behandelt + und –
double expression()
{
    double left = term();       // liest einen Token ein und wertet ihn aus
    Token t = ts.get();        // lies das nächste Token aus dem Token-Stream ein

    while(true) {    
        switch(t.kind) {
        case '+':
            left += term();    // werte Term aus und addiere
            t = ts.get();
            break;
        case '-':
            left -= term();    // werte Term aus und subtrahiere
            t = ts.get();
            break;
        default: 
            ts.putback(t);     // stelle t wieder zurück in den Token-Stream
            return left;       // keine weiteren + oder –; Antwort zurückliefern
        }
    }
}

//------------------------------------------------------------------------------

int main()
try
{
	double val = 0;
    while (cin) {
        Token t = ts.get();

        if (t.kind == 'q') break; // 'q' für &quot;verlassen&quot;
        if (t.kind == ';')        // ';' für &quot;jetzt ausgeben&quot;
            cout &lt;&lt; &quot;=&quot; &lt;&lt; val &lt;&lt; '\n';
        else
            ts.putback(t);
        val = expression();
    }
	keep_window_open();
}
catch (exception&amp; e) {
    cerr &lt;&lt; &quot;Fehler: &quot; &lt;&lt; e.what() &lt;&lt; '\n'; 
    keep_window_open();
    return 1;
}
catch (...) {
    cerr &lt;&lt; &quot;Hoppla: unbekannte Ausnahme!\n&quot;; 
    keep_window_open();
    return 2;
}
</code></pre>
<p>Die Fakultät an der Stelle einzuarbeiten, wo +-*/ bearbeitet werden, funktioniert in sofern nicht, da ja immer <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>2</mn><mo>+</mo><mn>3</mn><mo>!</mo><mo>=</mo><mn>2</mn><mo>+</mo><mo>(</mo><mn>3</mn><mo>!</mo><mo>)</mo></mrow><annotation encoding="application/x-tex">2+3!= 2+(3!)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.75em;"></span><span class="strut bottom" style="height:1em;vertical-align:-0.25em;"></span><span class="base textstyle uncramped"><span class="mord mathrm">2</span><span class="mbin">+</span><span class="mord mathrm">3</span><span class="mclose">!</span><span class="mrel">=</span><span class="mord mathrm">2</span><span class="mbin">+</span><span class="mopen">(</span><span class="mord mathrm">3</span><span class="mclose">!</span><span class="mclose">)</span></span></span></span> gelten soll, solange keine Klammern bei der Eingabe gesetzt werden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274870</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274870</guid><dc:creator><![CDATA[Lieschen Müller]]></dc:creator><pubDate>Mon, 26 Nov 2012 17:59:27 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Mon, 26 Nov 2012 18:22:53 GMT]]></title><description><![CDATA[<p>Wie wäre es mit einem ts.peek() aufruf, der nur schaut was kommt, das Token aber nicht entfernt? Aber ich hab nur kurz drübergeschaut.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274882</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274882</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Mon, 26 Nov 2012 18:22:53 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Mon, 26 Nov 2012 18:50:07 GMT]]></title><description><![CDATA[<p>Noch eine Korrektur zu seldons Variante:</p>
<pre><code>double factorial()
{
    double n = primary(); // Hier rekursiv weiter zu primary

    Token t = ts.get();

    while(t.kind == '!') 
	{
        n = fak(n);
	    t = ts.get();
    }

    ts.putback(t);

    return n;
}
</code></pre>
<p>Im while fehlte ein</p>
<pre><code>t = ts.get();
</code></pre>
<p>Sonst geht's in eine Endlosschleife der Fakultätsberechnung.</p>
<p>Hm, peek() klingt erstmal interessant. Muss ich mich mal reinlesen.</p>
<p>Edit: Ah, ich glaube, es geht - zumindest im Prinzip doch so wie von seldon vorgeschlagen. Mein Kompilier hat leider gemeckert, als ich nur Token t aufgerufen habe. Hab's darum so gemacht, wie hier in meinem Beispiel.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274896</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274896</guid><dc:creator><![CDATA[Lieschen Müller]]></dc:creator><pubDate>Mon, 26 Nov 2012 18:50:07 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Mon, 26 Nov 2012 19:48:20 GMT]]></title><description><![CDATA[<p>Ahh, siehst du. Die Kombination aus get()+putback() ist sozusagen das peek(), das ich meinte. Hätte ich genauer lesen müssen, sorry, mea culpa.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274923</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274923</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Mon, 26 Nov 2012 19:48:20 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Mon, 26 Nov 2012 20:37:36 GMT]]></title><description><![CDATA[<p>Nein, ich danke dir. Ich lern doch dazu. Ich bin auch erst später drauf gestoßen, dass es im Prinzip das gleiche ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2274931</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2274931</guid><dc:creator><![CDATA[Lieschen Müller]]></dc:creator><pubDate>Mon, 26 Nov 2012 20:37:36 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Wed, 28 Nov 2012 17:26:22 GMT]]></title><description><![CDATA[<p>P.S: &quot;Recdesc Parser&quot; meint einen <a href="http://de.wikipedia.org/wiki/Recursive_Descent_Parser" rel="nofollow">Recursive Descent Parser</a>, d.h. der LL-Parser wird implizit durch Aufruf der passenden Funktionen (expression, term, factor, primary) implementiert.<br />
Und dies geht nur rechtsrekursiv (bei linksrekursiven Beschreibungen entsteht sonst eine Endlosrekursion).</p>
<p>P.S. Die Grammatik müßte eigentlich bei einem rechtsrekursiven Parser so aussehen</p>
<pre><code>Ausdruck:
Term
Term &quot;+&quot; Ausdruck
Term &quot;-&quot; Ausdruck
</code></pre>
<p>(also Term und Ausdruck bei &quot;+&quot; und &quot;-&quot; vertauscht)</p>
<p>Noch ein P.S. Ich habe mal gerade im Buch &quot;Die C++ Programmiersprache&quot; (4. Auflage) nachgeschaut: dort ist die Grammatik auch linksrekursiv angegeben...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2275521</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2275521</guid><dc:creator><![CDATA[Th69]]></dc:creator><pubDate>Wed, 28 Nov 2012 17:26:22 GMT</pubDate></item><item><title><![CDATA[Reply to Fakultät in Taschenrechner implementieren on Wed, 28 Nov 2012 18:06:12 GMT]]></title><description><![CDATA[<p>Ehrlich gesagt ... hab ich das jetzt nicht verstanden. Werde mal drüber nachdenken.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2275540</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2275540</guid><dc:creator><![CDATA[Lieschen Müller]]></dc:creator><pubDate>Wed, 28 Nov 2012 18:06:12 GMT</pubDate></item></channel></rss>