Parser funkcji matematycznych

0

Witam,
Mam problem, który nie bardzo wiem jak rozwiązać. Napisałem program do obliczania wartości wyrażenia matematycznego na podstawie podanego łańcucha tekstowego. Program jest jednak ograniczony do podstawowych działań arytmetycznych takich jak:

  • dodawanie,
  • odejmowanie,
  • mnożenie,
  • dzielenie,
  • potęgowanie.
    Chciałbym jednak rozszerzyć możliwości programu o obliczanie bardziej złożonych wartości wejściowych, np fukcji sinus, cosinus, logarytm itp... Wykorzystuję algorytm odwrotnej notacji polskiej do zamiany wyrażenia na postać postfixową (beznawiasową) jednak nie wiem jak poradzić sobie z funkcjami. Czy jest jakiś prosty sposób? Czytałem, że powinienem dalej wykorzystywać ONP (nawet z funkcjami sin, cos itp...) jednak nie wiem jak się za to zabrać. Jakieś pomysły, rozwiązania?
1

Operatory też są funkcjami, więc większość aplikacji masz już gotową :-)
1 + 2 jest tym samym, co +(1, 2) - pokombinuj dalej z tym.

0

Rozumiem, że chodzi o algorytm przekształcania wyrażeń na ONP, a nie samo obliczanie na podstawie ONP.
Funkcje trygnonometryczne to po prostu operatory unarne (jednoargumentowe), trzeba im dobrze ustawić priorytet. Np. unarny minus ( np. do reprezentacji -1) ma priorytet wyższy niż mnożenie i dzielenie, a niższy niż potęgowanie. Wydaje mi się, że funkcje trygonometryczne powinny mieć jeszcze wyższy priorytet niż potęgowanie.

Obsługa funkcji podczas tworznia onp jest opisana tutaj: https://en.wikipedia.org/wiki/Shunting-yard_algorithm
Sama obsługa wykonania funkcji w notacji onp tak jak napisali koledzy - tak jak operatory.

0

Zobacz tutajhttps://github.com/lion137/Java-Numeric-Calculator?files=1
Wydaje sir, ze wystarczy zmienic funkcje eval , zeby zrzucala ze stosu jeden element I wykonywala operacje.

0
hydrant23 napisał(a):

Witam,
Mam problem, który nie bardzo wiem jak rozwiązać. Napisałem program do obliczania wartości wyrażenia matematycznego na podstawie podanego łańcucha tekstowego. Program jest jednak ograniczony do podstawowych działań arytmetycznych takich jak:

  • dodawanie,
  • odejmowanie,
  • mnożenie,
  • dzielenie,
  • potęgowanie.
    Chciałbym jednak rozszerzyć możliwości programu o obliczanie bardziej złożonych wartości wejściowych, np fukcji sinus, cosinus, logarytm itp... Wykorzystuję algorytm odwrotnej notacji polskiej do zamiany wyrażenia na postać postfixową (beznawiasową) jednak nie wiem jak poradzić sobie z funkcjami. Czy jest jakiś prosty sposób? Czytałem, że powinienem dalej wykorzystywać ONP (nawet z funkcjami sin, cos itp...) jednak nie wiem jak się za to zabrać. Jakieś pomysły, rozwiązania?

Kiedyś robiłem taki interpreter - w C++, więc mogę to sprzedać.

Przykład tablicy - definicji operatorów:

Symbol Symbole0[] = {
{ C_NUM, (TFun1)nic, L_OP,R_OP, 0, " " },
{ C_NUM, (TFun1)nic, L_OP,R_OP, 0, "pi"},
{ C_NUM, (TFun1)nic, L_OP,R_OP, 0, "e" },

	   { N_OTW, (TFun1)nic, L_OP,L_OP, 0,  "(" },
	   { N_ZAM, (TFun1)nic, R_OP,R_OP, 0,  ")" },

	     {1, sin,  L_OP,L_OP,   50,  "sin"  },
	     {1, asin, L_OP,L_OP,   50,  "asin" },
	     {1, sinh, L_OP,L_OP,   50,  "sinh" },

	     {1, cos,  L_OP,L_OP,   50,  "cos"  },
	     {1, acos, L_OP,L_OP,   50,  "acos" },
	     {1, cosh, L_OP,L_OP,   50,  "cosh" },

	     {1, tan,  L_OP,L_OP,   50,  "tg"   },
	     {1, atan, L_OP,L_OP,   50,  "atg"  },
	     {1, tanh, L_OP,L_OP,   50,  "tgh" },

	     {1, sqrt, L_OP,L_OP,  50,  "sqrt" },

	     {1, kwad, L_OP,L_OP,  50,  "sqr"  },

	     {1, log,  L_OP,L_OP,   50,  "ln"   },
	     {1, exp,  L_OP,L_OP,   50,  "exp"  },

         {1, fabs,  L_OP,L_OP,   50,  "abs"  },
         {1, sgn,   L_OP,L_OP,   50,  "sgn"  },
         {1, floor, L_OP,L_OP,   50,  "int"  },
         {1, rndf,   L_OP,L_OP,  50,  "rnd"  },


	   {',', (TFun1)nic,     R_OP,L_OP,   20, ","},
	   {'=', (TFun1)nic,     R_OP,L_OP,   20, "="},    // przypis
	   {'+', (TFun1)dodaj,   R_OP,L_OP,   21, "+"},
	   {'-', (TFun1)odejm,   R_OP,L_OP,   21, "-"},
	   {'*', (TFun1)mnoz,    R_OP,L_OP,   22, "*"},
	   {'/', (TFun1)dziel,   R_OP,L_OP,   22, "/"},
	   {'^', (TFun1)pow,     R_OP,L_OP,   30, "^"},

     {'%', (TFun1)fmod,     R_OP,L_OP,  22, "mod"},
     {'n', (TFun1)npok,     R_OP,L_OP,  20, "po"},


	   {C_NEG, neg,  L_OP,L_OP,  25, "-"},
	   {'!',   sil,  R_OP,R_OP,  90, "!"},


	   { C_NIC,  (TFun1)nic,    R_OP,0,    -1,  ""  },  //  == END
	   { C_NIC,  (TFun1)nic,    R_OP,0,    -1,  "=" },  //  == END

       { C_LVAL, NULL, L_OP,R_OP,   0,   "x"},  // zmienna -> nazwę można zmienić
       { C_LVAL, NULL, L_OP,R_OP,   0,   "t"},  // zmienna 2

	 };

Jak widać funkcji jest całkiem sporo.

Mam też to samo ale w wersji nieco rozszerzonej - w tym do operacji na zespolonych, np. piszesz:
2sin(2+i) + i^i/6

no i to się obliczy bez problemu.

Sam kod zajmuje niewiele - kilka prostych funkcji.

Problem polega na podziale operatorów na dwie klasy: prawostronne i lewostronne;

W sumie są tylko 4 typy operatorów/symboli w matematyce,
np. liczba/zmienna jest operatorem typu: LR, a wszelkie funkcje: sin, cos, itp. to operatory LL;
operacje dwuargumentowe, czyli te tradycyjne: +, -, *, /, ^, są typu RL,
no i są jeszcze te końcowe jak np. silnia - to są operatory typu RR.
Więcej nie ma.

1 użytkowników online, w tym zalogowanych: 0, gości: 1