<?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[Wie vom Benutzer einen Therm eingeben lassen?]]></title><description><![CDATA[<p>Hallo alle zusammen,<br />
ich will ein Programm schreiben, das mathematische Funktionen lösen kann.</p>
<p>Also z.B. Der Benutzer hat folgende Aufgabe:</p>
<p>F(x) = x * 2 + 5</p>
<p>Wie kann ich es programmieren, dass der Benutzer x * 2 + 5 selbst eingeben kann und das Programm danach das ganze als Therm anerkennt? Also dass danach für x eine andere Zahl eingesetzt werden kann und das ganze auch vom Programm berehnet wird?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/273875/wie-vom-benutzer-einen-therm-eingeben-lassen</link><generator>RSS for Node</generator><lastBuildDate>Thu, 27 Aug 2026 22:38:34 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/273875.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 14 Sep 2010 18:43:46 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Wie vom Benutzer einen Therm eingeben lassen? on Tue, 14 Sep 2010 18:43:46 GMT]]></title><description><![CDATA[<p>Hallo alle zusammen,<br />
ich will ein Programm schreiben, das mathematische Funktionen lösen kann.</p>
<p>Also z.B. Der Benutzer hat folgende Aufgabe:</p>
<p>F(x) = x * 2 + 5</p>
<p>Wie kann ich es programmieren, dass der Benutzer x * 2 + 5 selbst eingeben kann und das Programm danach das ganze als Therm anerkennt? Also dass danach für x eine andere Zahl eingesetzt werden kann und das ganze auch vom Programm berehnet wird?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1952640</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1952640</guid><dc:creator><![CDATA[Freakyboy]]></dc:creator><pubDate>Tue, 14 Sep 2010 18:43:46 GMT</pubDate></item><item><title><![CDATA[Reply to Wie vom Benutzer einen Therm eingeben lassen? on Tue, 14 Sep 2010 19:01:32 GMT]]></title><description><![CDATA[<p>Am Einfachsten mit dem <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Shunting-yard_algorithm" rel="nofollow">Shunting-Yard-Algorithmus</a>. Variablentoken werden dabei wie Zahlen behandelt und erst beim Auswerten des RPN-Ausdrucks durch die entsprechenden Werte ersetzt.</p>
<p>Ansonsten kannst du das ganze natürlich auch per Recdesc-Parser in einen abstrakten Syntaxbaum stopfen oder einen Parser-Generator bemühen (Boost.Spirit drängt sich da auf).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1952651</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1952651</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Tue, 14 Sep 2010 19:01:32 GMT</pubDate></item><item><title><![CDATA[Reply to Wie vom Benutzer einen Therm eingeben lassen? on Tue, 14 Sep 2010 19:07:16 GMT]]></title><description><![CDATA[<p>Mathematische ausdrücke lassen sich über eine relativ einfache Grammatik definieren. Du brauchst also einen Parser, der dir aus der Grammatik dann einen Parse-Baum liefert. Diesen Baum musst du dann an Hand der Operator-Präzedenz umsortieren. Wenn du das hast, kannst du dann den Baum rekursiv auswerten.</p>
<p>Ich fürchte nur, dass dir diese Beschreibung nicht wirklich weiter hilft. Es ist auch nicht unbedingt eine triviale Aufgabe. Wenn du das wirklich selber programmieren willst, dann schaue dir mal ein paar Sachen zum Thema &quot;Grammatiken&quot; und &quot;Parser&quot; an.</p>
<p>P.S.: Term schreibt man nicht mit &quot;Th&quot;.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1952652</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1952652</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Tue, 14 Sep 2010 19:07:16 GMT</pubDate></item><item><title><![CDATA[Reply to Wie vom Benutzer einen Therm eingeben lassen? on Tue, 14 Sep 2010 19:43:00 GMT]]></title><description><![CDATA[<p>Also ich kann dir nur sagen dass das ganze nicht so leicht ist, da ich auch selber gerade so etwas ähnliches mache als kleines Projekt. Jedoch mach ich das ganze erst mal ohne Variablen sondern nur mit Zahlen und arithmetischen Operatoren und Klammern und das ist schon schwer wie ich finde <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
<p>Aber schau mal hier, The69 hat hier son Parser parat <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f60b.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_savoring_food"
      title=":yum:"
      alt="😋"
    /><br />
<a href="http://www.c-plusplus.net/forum/viewtopic-var-p-is-1780654.html#1780654" rel="nofollow">http://www.c-plusplus.net/forum/viewtopic-var-p-is-1780654.html#1780654</a></p>
<p>Vielleicht hilft dir das <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Lg freeG</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1952673</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1952673</guid><dc:creator><![CDATA[fr33g]]></dc:creator><pubDate>Tue, 14 Sep 2010 19:43:00 GMT</pubDate></item><item><title><![CDATA[Reply to Wie vom Benutzer einen Therm eingeben lassen? on Tue, 14 Sep 2010 19:52:47 GMT]]></title><description><![CDATA[<p>Ich hab mal in meiner Kiste gekramt und das hier rausgezogen:</p>
<p>token.hh</p>
<pre><code class="language-cpp">#ifndef INCLUDED_TOKEN_HH
#define INCLUDED_TOKEN_HH

#include &lt;istream&gt;

struct token {
  enum id_t {
    op_id,
    num_id,
    var_id
  };

  union {
    char op;
    double x;
  } val;

  id_t type;
};

std::istream &amp;operator&gt;&gt;(std::istream &amp;in, token &amp;tok);

#endif
</code></pre>
<p><a href="http://token.cc" rel="nofollow">token.cc</a></p>
<pre><code class="language-cpp">#include &quot;token.hh&quot;

#include &quot;op_map.hh&quot;

#include &lt;cctype&gt;

std::istream &amp;operator&gt;&gt;(std::istream &amp;in, token &amp;tok) {
  char c;

  if(in &gt;&gt; c) {
    if(std::tolower(c) == 'x') {
      tok.type = token::var_id;
    } else if(std::isdigit(c)) {
      in.unget();

      double x;
      if(in &gt;&gt; x) {
        tok.val.x = x;
        tok.type = token::num_id;
      }
    } else if(op_map::instance().is_valid(c)) {
      tok.val.op = c;
      tok.type = token::op_id;
    } else {
      in.setstate(in.rdstate() | std::istream::failbit);
    }
  }

  return in;
}
</code></pre>
<p>op_map.hh</p>
<pre><code class="language-cpp">#ifndef INCLUDED_OP_MAP_HH
#define INCLUDED_OP_MAP_HH

#include &lt;map&gt;
#include &lt;utility&gt;

typedef double(*eval_func_t)(double, double);
typedef std::pair&lt;int, eval_func_t&gt; op_record_t;

class op_map {
public:
  op_map();

  bool        is_valid(char c) const;
  int         priority(char c) const;
  eval_func_t function(char c) const;

  static op_map const &amp;instance();

private:
  std::map&lt;char, op_record_t&gt; data_;
};

#endif
</code></pre>
<p>op_map.cc</p>
<pre><code class="language-cpp">#include &quot;op_map.hh&quot;

#include &lt;cmath&gt;
#include &lt;stdexcept&gt;

template&lt;char op&gt; double eval_func(double, double) { throw std::invalid_argument(&quot;Ungültiger Operator&quot;); }

template&lt;&gt; double eval_func&lt;'+'&gt;(double x, double y) { return x + y; }
template&lt;&gt; double eval_func&lt;'-'&gt;(double x, double y) { return x - y; }

template&lt;&gt; double eval_func&lt;'*'&gt;(double x, double y) { return x * y; }
template&lt;&gt; double eval_func&lt;'/'&gt;(double x, double y) { return x / y; }

template&lt;&gt; double eval_func&lt;'^'&gt;(double x, double y) { return std::pow(x, y); }

op_map::op_map() {
  data_['('] = op_record_t(-1, eval_func&lt;'('&gt;);
  data_[')'] = op_record_t(-1, eval_func&lt;')'&gt;);

  data_['+'] = op_record_t( 0, eval_func&lt;'+'&gt;);
  data_['-'] = op_record_t( 0, eval_func&lt;'-'&gt;);

  data_['*'] = op_record_t( 1, eval_func&lt;'*'&gt;);
  data_['/'] = op_record_t( 1, eval_func&lt;'/'&gt;);

  data_['^'] = op_record_t( 2, eval_func&lt;'^'&gt;);
}

bool        op_map::is_valid(char c) const { return data_.find(c) != data_.end(); }
int         op_map::priority(char c) const { return data_.find(c)-&gt;second.first ; }
eval_func_t op_map::function(char c) const { return data_.find(c)-&gt;second.second; }

op_map const &amp;op_map::instance() {
  static const op_map me;
  return me;
}
</code></pre>
<p>read_type.hh</p>
<pre><code class="language-cpp">#ifndef INCLUDED_READ_TYPE_HH
#define INCLUDED_READ_TYPE_HH

#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;string&gt;

template&lt;typename result_t&gt;
result_t read_type_ref(result_t &amp;dest,
                       std::string const &amp;prompt,
                       std::istream &amp;in  = std::cin,
                       std::ostream &amp;out = std::cout) {
  std::istringstream parser;
  std::string line;

  do {
    parser.clear();

    out &lt;&lt; prompt &lt;&lt; std::flush;

    std::getline(in, line);

    parser.str(line);
    parser &gt;&gt; dest;
  } while(!parser);

  return dest;
}

template&lt;typename result_t&gt;
result_t read_type(std::string const &amp;prompt,
                   std::istream &amp;in  = std::cin,
                   std::ostream &amp;out = std::cout) {
  result_t result;
  return read_type_ref(result, prompt, in, out);
}

#endif
</code></pre>
<p><a href="http://calc.cc" rel="nofollow">calc.cc</a></p>
<pre><code class="language-cpp">#include &quot;op_map.hh&quot;
#include &quot;read_type.hh&quot;
#include &quot;token.hh&quot;

#include &lt;iomanip&gt;
#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;stack&gt;
#include &lt;stdexcept&gt;
#include &lt;string&gt;

template&lt;typename T&gt; T top_and_pop(std::stack&lt;T&gt; &amp;s) {
  T ret = s.top();
  s.pop();
  return ret;
}

void perform_top_operation(std::stack&lt;double&gt; &amp;num_stack,
                           std::stack&lt;char&gt;   &amp; op_stack) {
  if(num_stack.size() &lt; 2 || op_stack.empty()) {
    throw std::invalid_argument(&quot;Ungültiger Ausdruck&quot;);
  }

  char op;
  double x, y;

  op = top_and_pop(op_stack);
  x  = top_and_pop(num_stack);
  y  = top_and_pop(num_stack);

  num_stack.push(op_map::instance().function(op)(y, x));
}                           

double solve(std::string equation, double var_x) {
  std::stack&lt;double&gt; num_stack;
  std::stack&lt;char  &gt;  op_stack;

  std::istringstream is(equation);
  token tok;

  while(is &gt;&gt; tok) {
    switch(tok.type) {
    case token::var_id:
      {
        num_stack.push(var_x);
        break;
      }
    case token::num_id:
      {
        num_stack.push(tok.val.x);
        break;
      }
    case token::op_id:
      {
        char op = tok.val.op;
        if(op == '(') {
          op_stack.push(op);
        } else if(op == ')') {
          // Lazy-Evaluation, damit op_stack.top() nicht bei leerem Stack
          // ausgeführt wird. Das funktioniert, weil perform_top_operation bei
          // leerem op_stack eine Exception schmeißt.
          while(op_stack.empty() || op_stack.top() != '(') {
            perform_top_operation(num_stack, op_stack);
          } 

          op_stack.pop();
        } else {
          while(op != '^' &amp;&amp; // rechtsassoziativ, derzeit hoechste Priorität
                !op_stack.empty() &amp;&amp;
                op_map::instance().priority(op) &lt;= op_map::instance().priority(op_stack.top())) {
            perform_top_operation(num_stack, op_stack);
          }
          op_stack.push(op);
        }
        break;
      }
    }
  }

  // num_stack.empty() ist nur true, wenn ein leerer
  // Ausdruck bzw. (), (()) etc. angegeben wurde - 
  // perform_top_operation schmeißt dann einen Fehler (s.o.)
  while(!op_stack.empty() || num_stack.empty()) {
    perform_top_operation(num_stack, op_stack);
  }

  return num_stack.top();
}

int main() {
  std::string equation;

  while(std::getline(std::cin, equation)) {
    if(equation == &quot;quit&quot; ||
       equation == &quot;exit&quot;) {
      break;
    }

    double x = read_type&lt;double&gt;(&quot;x = &quot;);

    try {
      std::cout &lt;&lt; std::setprecision(15) &lt;&lt; solve(equation, x) &lt;&lt; std::endl;
    } catch(std::invalid_argument &amp;e) {
      std::cerr &lt;&lt; e.what() &lt;&lt; std::endl;
    }
  }
}
</code></pre>
<p>Makefile</p>
<pre><code>#!/usr/bin/make

TARGET   = calc

CXX      = g++
CXXFLAGS = -Wall -Wextra -pedantic -O2

LIBS     =

SRCS     = $(wildcard *.cc)
OBJS     = $(SRCS:%.cc=%.o)

DEPFILE  = .depend

all: dep $(TARGET)

dep: $(DEPFILE)

$(DEPFILE): $(SRCS)
        $(CXX) -MM $+ &gt; $@

-include $(DEPFILE)

$(TARGET): $(OBJS)
        $(CXX) $(CXXFLAGS) $(LIBS) $+ -o $@

clean:
        rm $(OBJS)

distclean: clean
        rm $(TARGET)
        rm $(DEPFILE)

.PHONY: all dep clean distclean
</code></pre>
<p>Das ganze implementiert den Shunting-Yard-Algorithmus derart, dass beim Umstellen des Ausdrucks gleichzeitig ausgewertet wird. Wenn der selbe Ausdruck oft mit verschiedenen x ausgewertet werden soll, ist das natürlich nicht der performanteste Ansatz, und es gibt ein paar kleinere Unschönheiten in der Implementierung (die Sonderbehandlung für ^ beispielsweise), aber in der Art könnte man das machen, ohne gleich große Kanonen auszupacken.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1952682</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1952682</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Tue, 14 Sep 2010 19:52:47 GMT</pubDate></item></channel></rss>