#c #formula
#c #формула
Вопрос:
В настоящее время я работаю над этим проектом под названием «expression evaluator», и у меня есть несколько вопросов о том, как его кодировать.
Прежде всего, что делает этот «вычислитель выражений»? Он просто вычисляет вставленное вами выражение, оно должно поддерживать:
- круглые круглые скобки
- операторы: , -, /, *, <>, =, <=, >=, или, и, xor, не, мод,
- все математические функции отсюда
- вещественная, целочисленная и логическая константа (1, 1.1, -1, true, false и т. Д.)
- обычные переменные, такие как var, например: 1 var // переменные можно использовать следующим образом: «var = 50 1 var», и он должен выводить 51.
В настоящее время мне удалось преобразовать строку в постфиксную нотацию (перевернутая польская нотация) и оценить ее, но в настоящее время она поддерживает только ( , -, *, /, ^) и только вещественные и целочисленные константы.
Как я мог бы добавить поддержку для остальных операторов / переменных / формул?
Я действительно пытался добавить поддержку переменных / формул, но это работает только для базовых выражений, таких как: pow (1, 3) 2, это выводит 3 (TRUE). Если я попробую более сложные выражения, это произойдет примерно так: pow (pow (2, 3), 2), это выводит 512, что неверно, оно должно выводить 64.
Вот мой код, чтобы вы могли проверить его самостоятельно.
#include <algorithm>
#include <cmath>
#include <fstream>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
// Setari
#define __DEBUG__ // Afiseaza informatii despre procesul de rezolvare.
#define __SUPPORT_DOUBLE__ // Activeaza suportul pentru numere reale.
// Variabile
std::vector<std::string> Infix;
std::stack<std::string> operators;
std::stack<std::string> Rezultat;
// Salvez operatorii si nivelul lor de prioritate intr-un dictioar pentru a face procesul de identificare mai rapid
std::map<std::string, short> Operators = { {" ", 1}, {"-", 1}, {"*", 2}, {"/", 2}, {"^", 3}, {"pow", 3}, {"==", 4}, {"=", 5} };
std::ifstream fin("eval.in");
std::ofstream fout("eval.out");
// Functii
// Caut in dictionarul 'Operators' operatorul si, daca-l gasesc returnez prioritatea acestuia.
int CheckOperator(const std::stringamp; op){
const autoamp; it = Operators.find(op);
if (it != Operators.end())
return it->second;
return 0;
}
int main(){
std::string expr, token;
while (std::getline(fin, token))
expr.append(token);
fin.close();
// Analizez expresie si sterg caracterele inutile( ).
expr.erase(std::remove_if(expr.begin(), expr.end(), [](const charamp; c){ return c == '\'; }), expr.end());
// Transform expresia in expresie postfix.
for (size_t i = 0; i < expr.length(); i){
char c = expr[i];
token.clear();
int prioritate = 0;
token = c;
if (isdigit(c))
{
for ( i; i < expr.length(); i){
c = expr[i];
#if defined(__SUPPORT_DOUBLE__)
if (!isdigit(c) amp;amp; c != '.')
break;
#else
if (!isdigit(c))
break;
#endif
token = c;
}
--i;
Infix.push_back(token);
}
else if(isalpha(c))
{
for ( i; i < expr.length(); i){
c = expr[i];
if (!isalnum(c))
break;
token = c;
}
std::cout << "Verificare: " << token << 'n';
--i;
if (CheckOperator(token))
operators.push(token);
else
Infix.push_back(token);
}
else if((prioritate = CheckOperator(token))){
bool numar = false;
for ( i; i < expr.length(); i){
c = expr[i];
token = c;
#if defined(__SUPPORT_DOUBLE__)
if (!CheckOperator(token) amp;amp; !isdigit(c) amp;amp; c != '.'){
token.erase(token.length() - 1, token.length());
break;
}
#else
if (!CheckOperator(token) amp;amp; !isdigit(c)){
token.erase(token.length() - 1, token.length());
break;
}
#endif
if (isdigit(c))
numar = true;
}
--i;
if (!numar){
while(!operators.empty() amp;amp; CheckOperator(operators.top()) >= prioritate)
{
Infix.push_back(operators.top());
operators.pop();
}
operators.push(token);
}
else
{
Infix.push_back(token);
}
}
else if (c == '(')
{
operators.push("(");
}
else if (c == ')')
{
while (!operators.empty())
{
if (operators.top() == "("){
operators.pop();
break;
}
Infix.push_back(operators.top());
operators.pop();
}
}
}
while (!operators.empty())
{
Infix.push_back(operators.top());
operators.pop();
}
#if defined(__DEBUG__)
for (const autoamp; ex : Infix)
fout << ex << ' ';
fout << 'n';
#endif
autoamp; it = Infix.begin();
for(; it != Infix.end(); it)
{
if (CheckOperator(*it))
{
if (*it == " ")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a b));
}
else if(*it == "-")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a - b));
}
else if(*it == "*")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a * b));
}
else if(*it == "/")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a / b));
}
else if(*it == "^")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(std::powl(a, b)));
}
else if(*it == "==")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a == b));
}
else if(*it == "pow")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(std::powl(a, b)));
}
}
else
{
Rezultat.push(*it);
}
}
#if defined(__SUPPORT_DOUBLE__)
fout << Rezultat.top() << 'n';
#else
fout << std::stol(Rezultat.top()) << 'n';
#endif
return 0;
}
Спасибо!
Редактировать: я опубликовал решение на Github, если оно вам нужно.
Ответ №1:
Не совсем понятно, что вы подразумеваете под «формулами».
Переменные в алгоритме маневровой площадки ведут себя точно так же, как числа, без какой-либо разницы.
Присваивание x = y
можно рассматривать как просто другой вид выражения. Вы хотите добавить =
оператор в свой список поддерживаемых операторов. Просто выберите его приоритет.
Очевидно, что оценщику необходимо отличать переменные от констант и выражений, чтобы он мог сигнализировать об ошибке в каждом из этих случаев:
x 2 (undefined x)
2 = 5 (assignment to non-variable)
(1 2) = 3 (same)
Обратите внимание, что вы хотите иметь возможность оценивать несколько выражений сейчас, чтобы вы могли оценивать var = 50
, а затем 1 var
как два отдельных выражения. Разработайте способ их разделения. ;
Символ будет отлично работать для этой цели.
Также обратите внимание, что =
использование как для сравнения, так и для присваивания действительно не рекомендуется. Вы хотите либо изменить сравнение ==
, как это делает большинство языков программирования в наши дни, либо изменить назначение, чтобы использовать какой-либо другой символ, скажем :=
, или <-
.
Комментарии:
1. Здравствуйте, под формулами я подразумеваю математические формулы (pow, floor и т. Д. (я разместил ссылку)). Кроме того, я уже использую оператор «==» для сравнения, и он работает правильно.
2. Обычно они называются функциями, а не формулами. Я предлагаю делать что-то одно за раз, добавлять переменные, а затем думать о добавлении функций.
3. Спасибо! Мой подход был немного неправильным, поэтому я перекодировал его и сумел заставить его работать так, как предполагалось. Вы можете проверить код здесь , если вам интересно.