Szukam prosty sposób ocenić proste wyrażenie matematyczne z łańcucha, tak:Ocenianie wyrażeń arytmetycznych z ciągiem w C++
3 * 2 + 4 * 1 + (4 + 9) * 6
chcę tylko +
i *
operacyjna powiększona (
i )
znaki. I *
ma wyższy priorytet niż +
.
Szukam prosty sposób ocenić proste wyrażenie matematyczne z łańcucha, tak:Ocenianie wyrażeń arytmetycznych z ciągiem w C++
3 * 2 + 4 * 1 + (4 + 9) * 6
chcę tylko +
i *
operacyjna powiększona (
i )
znaki. I *
ma wyższy priorytet niż +
.
myślę szukasz prostego recursive descent parser.
Oto bardzo prosty przykład:
const char * expressionToParse = "3*2+4*1+(4+9)*6";
char peek()
{
return *expressionToParse;
}
char get()
{
return *expressionToParse++;
}
int expression();
int number()
{
int result = get() - '0';
while (peek() >= '0' && peek() <= '9')
{
result = 10*result + get() - '0';
}
return result;
}
int factor()
{
if (peek() >= '0' && peek() <= '9')
return number();
else if (peek() == '(')
{
get(); // '('
int result = expression();
get(); // ')'
return result;
}
else if (peek() == '-')
{
get();
return -factor();
}
return 0; // error
}
int term()
{
int result = factor();
while (peek() == '*' || peek() == '/')
if (get() == '*')
result *= factor();
else
result /= factor();
return result;
}
int expression()
{
int result = term();
while (peek() == '+' || peek() == '-')
if (get() == '+')
result += term();
else
result -= term();
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
int result = expression();
return 0;
}
Nie sądzę, że rekursywna przyzwoitość jest dobra dla arytmetyki, ponieważ jest całkowicie rekurencyjna. – Pubby
3 lata później - przepraszam za zombification! - w tym kodzie jest BŁĄD. Przekazanie temu wyrażeniu "-1 + 2" daje wynik -3. Aby to naprawić, w funkcji "factor()" obsługa bitów (peek() == '-') musi zwracać czynnik(), a nie wyrażenie(). –
@JulianGold masz rację, dzięki. Dokona edycji. – Henrik
myślę, że można znaleźć odpowiedź w tym wątku: Evaluating string "3*(4+2)" yield int 18
Albo można dać spróbować tej biblioteki: http://weblogs.asp.net/pwelter34/archive/2007/05/05/calculator-net-calculator-that-evaluates-math-expressions.aspx
Rozważ użycie ducha doładowania:
http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundamental/ast_calc.cpp
Ten przykładowy kod jest nieco stary i nie będzie się nawet kompilował z ostatnimi wersjami ducha boost. Jest to nowszy przykład na tej samej zasadzie: http://www.boost.org/doc/libs/1_41_0/libs/spirit/example/qi/calc2_ast.cpp – smocking
Oto miły mały prezentacja na drzewach oceny dla kompleksu (nie naprawdę: P) wyrażenia matematyczne:
http://courses.cs.vt.edu/~cs1044/spring01/cstruble/notes/6.complexexpr.pdf
Przeprowadzi Cię przez to w dobrym stylu;)
Napisałem bardzo proste narzędzie do sprawdzania wyrażeń w języku C# (minimalne zmiany są wymagane, aby było zgodne z C++). Opiera się na metodzie budowania drzewa ekspresji, tylko to drzewo nie jest faktycznie zbudowane, ale wszystkie węzły są oceniane na miejscu.
Można go znaleźć pod tym adresem: Simple Arithmetic Expression Evaluator
Podczas przeszukiwania biblioteki dla podobnego zadania znalazłem libmatheval. Wydaje się być właściwą rzeczą. Niestety, GPL, co jest dla mnie nie do przyjęcia.
import java.util.Deque;
import java.util.LinkedList;
public class EvaluateArithmeticExpression {
public static void main(String[] args) {
System.out.println(evaluate("-4*2/2^3+3")==-4*2/Math.pow(2, 3)+3);
System.out.println(evaluate("12*1314/(1*4)+300")==12*1314/(1*4)+300);
System.out.println(evaluate("123-(14*4)/4+300")==123-(14*4)/4+300);
System.out.println(evaluate("12*4+300")==12*4+300);
}
public static int evaluate(String s){
Deque<Integer> vStack= new LinkedList<>();
Deque<Character> opStack= new LinkedList<>();
int i=0;
while(i<s.length()){
if(isNum(s,i))
i=getNum(s,vStack,i);
else if(isOp(s,i))
i=doOp(s,opStack,vStack,i);
}
doOp(opStack,vStack);
return vStack.pop();
}
private static int getNum(String s, Deque<Integer> vStack,int i){
int sign=1;
if(s.charAt(i)=='-' || s.charAt(i)=='+')
sign=s.charAt(i++)=='-'?-1:1;
int val=0;
while(i<s.length() && isNum(s,i))
val=val*10+s.charAt(i++)-'0';
vStack.push(sign*val);
return i;
}
private static int doOp(String s, Deque<Character> opStack,Deque<Integer> vStack,int i){
char op=s.charAt(i);
if(op=='(')
opStack.push(op);
else{
if(op==')'){
while(!opStack.isEmpty() && opStack.peekFirst()!='(')
doOp(opStack,vStack);
opStack.pop();
}
else{
while(!opStack.isEmpty() && prior(op)<=prior(opStack.peekFirst()))
doOp(opStack,vStack);
opStack.push(op);
}
}
return i+1;
}
private static int prior(char op){
switch(op){
case '+':
case '-': return 1;
case '*':
case '/': return 2;
case '^': return 4;
}
return 0;
}
private static void doOp(Deque<Character> opStack,Deque<Integer> vStack){
int b=vStack.isEmpty()?0:vStack.pop();
int a=vStack.isEmpty()?0:vStack.pop();
char op=opStack.pop();
int res=evaluate(a,b,op);
vStack.push(res);
}
private static int evaluate(int a, int b, char op){
switch(op){
case '+': return a+b;
case '-': return a-b;
case '/': return a/b;
case '*': return a*b;
case '^': return (int)Math.pow(a,b);
}
return 0;
}
private static boolean isNum(String s, int i){
return '0'<=s.charAt(i) && s.charAt(i)<='9';
}
private static boolean isOp(String s, int i){
return "()+-*/^".contains(String.valueOf(s.charAt(i)));
}
}
Kod powinien znajdować się w C++ ... – Eenoku
Można spróbować: http://partow.net/programming/exprtk/index.html
To powinna być zaakceptowana odpowiedź! 'exprtk' jest naprawdę potężny i prosty, warto go najpierw wypróbować! –
Wystarczy dodać inną alternatywę, za trudny TinyExpr tego problemu. Jest otwarty i samowystarczalny w jednym pliku kodu źródłowego. W rzeczywistości jest napisane w C, ale będzie kompilować czysto jak C++ w moim doświadczeniu.
rozwiązywania przykład wyraz z góry jest tak proste, jak:
#include "tinyexpr.h"
#include <stdio.h>
int main()
{
double answer = te_interp("3*2+4*1+(4+9)*6", 0);
printf("Answer is %f\n", answer);
return 0;
}
Czy to zadanie domowe? – 0605002
... a jakie jest twoje pytanie? – 0605002
Prawdopodobnie najlepiej jest go ocenić, analizując wyrażenie w jakiejś strukturze drzewa. –