Ecuación matemática como cadena para revertir el analizador de notación polaca -- # campo con parsing campo con math-expression-eval camp codereview Relacionados El problema

Math equation as string to reverse Polish notation parser


3
vote

problema

Español

He creado un programa de consola donde los usuarios escriben una ecuación de matemáticas, como 5+4-6 o (5+16(8-4))/16 que sigue el orden de las operaciones. La ecuación se envía a una matriz de caracteres que luego se analiza. Si se encuentra un o #2 / .3 , el Char se coloca en un búfer. El búfer se tokenizado en una clase de token, seguido del propio operador que se está tokenizado. El programa funciona bellamente y como se esperaba. Las excepciones y los errores aún deben manejarse donde ahora solo está escribiendo en la consola y continuando.

Lo que estoy buscando para hacerlo es agregar en funciones más altas, más en línea con una calculadora científica, comenzando con las constantes como E y PI, luego se mudan a las funciones de TRIG. Está al manejar las funciones con las que tengo un problema con.

¿Recomendaría almacenar los caracteres en un búfer similar al # 's y tratarlos como una función si se encuentra un 998877776655544334 inmediatamente después, y una constante de otra manera? ¿Qué sugieres? Además, ¿qué podría mejorar?

programa.cs

  using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CalcTest.Core;  namespace CalcTest {     class Program     {         static Calculator calculator;         static void Main(string[] args)         {             calculator = new Calculator();             calculator.Entry();         }     } }   

enums.cs

  using CalcTest; using CalcTest.Core;  namespace CalcTest.Core {     public enum TokenType     {         Value,         Operand,         Function,         Paramater,         Variable     } }   

token.cs

  using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace CalcTest.Core {     public class Token     {         private TokenType type;         private string val;          public TokenType TYPE         {             get { return type; }             set { type = value; }         }         public string VALUE         {             get { return val; }             set { val = value; }         }          public Token(TokenType t, string s)         {             this.TYPE = t;             this.VALUE = s;             //Write();         }          public override string ToString()         {             return String.Format("Token:= Type: {0}; Value: {1}", TYPE.ToString(), VALUE);         }          private void Write()         {             Console.WriteLine(this.ToString());         }     } }   

calculator.cs

  using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace CalcTest.Core {     public class Calculator     {         private Stack<Token> tokenStack;         private Queue<Token> tokenQue;         private char[] buffer;         private int bufferLoc;         private TokenType? priorType;          public Calculator()          {             tokenQue = new Queue<Token>();             tokenStack = new Stack<Token>();             buffer = new char[100];             bufferLoc = 0;             priorType = null;         }          #region BasicFunctions         private Token Addition(Token t1, Token t2)         {             //Console.WriteLine("Addition:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double sum = arg1 + arg2;              return CreateToken(TokenType.Value, sum.ToString());         }//end Addition         private Token Subtract(Token t1, Token t2)         {             //Console.WriteLine("Subtraction:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double sub = arg1 - arg2;              return CreateToken(TokenType.Value, sub.ToString());         }//end Subtract         private Token Multiplication(Token t1, Token t2)         {             //Console.WriteLine("Multiplication:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double multi = arg1 * arg2;              return CreateToken(TokenType.Value, multi.ToString());         }//end Multiplication         private Token Division(Token t1, Token t2)         {             //Console.WriteLine("Division:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double div = arg1/arg2;              return CreateToken(TokenType.Value, div.ToString());         }//end Division         private Token Power(Token t1, Token t2)         {             //Console.WriteLine("Power:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double power = Math.Pow(arg1,arg2);              return CreateToken(TokenType.Value, power.ToString());         }//end Power         #endregion          public void Entry()         {             char[] equation = new char[1];             while (true)             {                 Array.Clear(equation, 0, equation.Length);                 equation = Console.ReadLine().ToCharArray();                 ParseEquation(equation);                  foreach (var t in tokenQue)                 {                     Console.Write(t.VALUE + ", ");                 }                 Console.WriteLine();                  EvalEquation();                  if (tokenStack.Count > 0)                     Console.WriteLine(tokenStack.Pop().VALUE);                 else                     Console.WriteLine("Nothing returned");                  tokenStack.Clear();                 tokenQue.Clear();             }         }//end Entry          #region EvalFunctions         private void EvalEquation()         {             Token temp = null;              while (tokenQue.Count != 0)             {                 temp = tokenQue.Dequeue();                  if (temp.TYPE == TokenType.Value)                     tokenStack.Push(temp);                 else                     OpperationSwitch(temp);             }         }//end EvalEquation         private void OpperationSwitch(Token t)         {             Token ret = null;             if (tokenStack.Count >= 2)             {                 Token t2 = tokenStack.Pop();                 Token t1 = tokenStack.Pop();                  switch (t.VALUE)                 {                     case ("*"):                         ret = Multiplication(t1, t2);                         break;                     case ("/"):                         ret = Division(t1, t2);                         break;                     case ("+"):                         ret = Addition(t1, t2);                         break;                     case ("-"):                         ret = Subtract(t1, t2);                         break;                     case ("^"):                         ret = Power(t1, t2);                         break;                 }                  if (ret != null)                     tokenStack.Push(ret);             }             else             {                 Console.WriteLine("Error in OpperationSwitch");                 //error code             }         }//end OpperationSwitch         #endregion          #region ParserFunctions         private void ParseEquation(char[] equation)         {             for (int i = 0; i < equation.Length; i++)             {                 priorType = null;                 //Console.WriteLine("ParseEquation:= i: {0} ; Char: {1}", i, equation[i]);                 if (char.IsDigit(equation[i]) || equation[i] == '.')                 {                     //executes if # or .                     AddToBuffer(equation[i]);                 }                 else                 {                     //if buffer has data, create token, place in queue, clear buffer, and set prior type.                     if (bufferLoc != 0)                     {                         tokenQue.Enqueue(CreateToken(TokenType.Value, new string(buffer, 0, bufferLoc)));                         Array.Clear(buffer, 0, bufferLoc);                         bufferLoc = 0;                         priorType = TokenType.Value;                     }                     //handles operands                     OperationHandler(equation[i]);                 }//end else-if             }//end while              //creates a token of anything remaining in the buffer, and queues it             if (bufferLoc != 0)             {                 tokenQue.Enqueue(CreateToken(TokenType.Value, new string(buffer, 0, bufferLoc)));                 Array.Clear(buffer, 0, bufferLoc);                 bufferLoc = 0;             }              //moves anything remaining on the tokenStack to the que             while (tokenStack.Count > 0)             {                 Token temp = tokenStack.Pop();                  if (temp.VALUE == "(")                 {                     //will only run in case of unpaired ()                     Console.WriteLine("Error with '(' in ParseEquation");                     //error code                 }                 tokenQue.Enqueue(temp);             }         }//end ParseEquation         private void OperationHandler(char opp)         {             if (opp == ')')             {                 //runs if the opp is )                 //Console.WriteLine("Entering ')' section of OperationHandler");                 Token temp = null;                 bool found = false;                  //cycles until the most recent ( is found. If not found, error.                 while (tokenStack.Count != 0)                 {                     temp = tokenStack.Pop();                     if (temp.VALUE == "(")                     {                         found = true;                         return;                     }                     else                     {                         tokenQue.Enqueue(temp);                     }                 }                  if (!found)                 {                     Console.WriteLine("Error with '(' section of OperationHandler");                     //error code                 }             }             else             {                 Token temp = CreateToken(TokenType.Operand, opp.ToString());                  //creates a multiplication incase of implicite multiplication. Ex: 5(4) => 5*4                 if (opp == '(' && priorType == TokenType.Value)                 {                     //Console.WriteLine("Creating a multiplication");                     tokenStack.Push(CreateToken(TokenType.Operand, "*"));                 }                  if (tokenStack.Count == 0)                 {                     //runs if stack is empty                     tokenStack.Push(temp);                 }                 else                 {                     OrderOfOpp(temp);                 }             }         }//end OperationHandler         private void OrderOfOpp(Token t)         {             string tempVal = null;             Dictionary<string, int> oppDic = new Dictionary<string, int>() {{"(",4 }, {"^",3},{"*",2},{"/",2},{"+",1},{"-",1}};             bool done = false;              while (!done || tokenStack.Count == 0)             {                 tempVal = tokenStack.Peek().VALUE;                  if (tempVal == "(")                 {                     //if most recent push to stack was (, auto push t to stack                     tokenStack.Push(t);                     done = true;                 }                 else                 {                     if (oppDic[t.VALUE] >= oppDic[tempVal])                     {                         //if the t token has a higher precident then the tempVal (Obtained from peek), pushes t to que                         tokenStack.Push(t);                         done = true;                     }                     else                     {                         //if the tempVal has a higher precident then pop and enqueue                         tokenQue.Enqueue(tokenStack.Pop());                     }                 }                  if (tokenStack.Count == 0)                 {                     //if stack is empty, push to stack                     tokenStack.Push(t);                     done = true;                 }             }//end while              if (!done)             {                 Console.WriteLine("Error in OrderOfOpp");                 //error code             }         }//end OrderOfOpp         #endregion          #region HelperFunctions         private void AddToBuffer(char add)         {             buffer[bufferLoc] = add;             bufferLoc++;         }//end AddToBuffer         private Token CreateToken(TokenType type, string value)         {             return new Token(type, value);         }//end CreateToken         #endregion     } }   
Original en ingles

I have created a console program where users type in a math equation such as 5+4-6 or (5+16(8-4))/16 that follows order of operations. The equation is sent to a char array that is then parsed. If a # or . is encountered, the char is placed into a buffer. The buffer is tokenized into a token class, followed by the operator itself being tokenized. The program works beautifully and as expected. Exceptions and errors still need to be handled where right now it is only writing to the console and continuing.

What I am looking to do next is add in higher functions, more in-line with a scientific calculator, starting with the constants such as e and pi, then moving into trig functions. It is in handling the functions that I am having an issue with.

Would you recommend storing the chars in a buffer similar to the #'s and treat them as a function if a ) is found immediately following, and a constant otherwise? What would you suggest? Also, what could I improve upon?

PROGRAM.CS

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CalcTest.Core;  namespace CalcTest {     class Program     {         static Calculator calculator;         static void Main(string[] args)         {             calculator = new Calculator();             calculator.Entry();         }     } } 

ENUMS.CS

using CalcTest; using CalcTest.Core;  namespace CalcTest.Core {     public enum TokenType     {         Value,         Operand,         Function,         Paramater,         Variable     } } 

TOKEN.CS

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace CalcTest.Core {     public class Token     {         private TokenType type;         private string val;          public TokenType TYPE         {             get { return type; }             set { type = value; }         }         public string VALUE         {             get { return val; }             set { val = value; }         }          public Token(TokenType t, string s)         {             this.TYPE = t;             this.VALUE = s;             //Write();         }          public override string ToString()         {             return String.Format("Token:= Type: {0}; Value: {1}", TYPE.ToString(), VALUE);         }          private void Write()         {             Console.WriteLine(this.ToString());         }     } } 

CALCULATOR.CS

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace CalcTest.Core {     public class Calculator     {         private Stack<Token> tokenStack;         private Queue<Token> tokenQue;         private char[] buffer;         private int bufferLoc;         private TokenType? priorType;          public Calculator()          {             tokenQue = new Queue<Token>();             tokenStack = new Stack<Token>();             buffer = new char[100];             bufferLoc = 0;             priorType = null;         }          #region BasicFunctions         private Token Addition(Token t1, Token t2)         {             //Console.WriteLine("Addition:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double sum = arg1 + arg2;              return CreateToken(TokenType.Value, sum.ToString());         }//end Addition         private Token Subtract(Token t1, Token t2)         {             //Console.WriteLine("Subtraction:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double sub = arg1 - arg2;              return CreateToken(TokenType.Value, sub.ToString());         }//end Subtract         private Token Multiplication(Token t1, Token t2)         {             //Console.WriteLine("Multiplication:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double multi = arg1 * arg2;              return CreateToken(TokenType.Value, multi.ToString());         }//end Multiplication         private Token Division(Token t1, Token t2)         {             //Console.WriteLine("Division:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double div = arg1/arg2;              return CreateToken(TokenType.Value, div.ToString());         }//end Division         private Token Power(Token t1, Token t2)         {             //Console.WriteLine("Power:= Arg1: {0}; Arg2: {1}", t1.VALUE, t2.VALUE);             double arg1 = double.Parse(t1.VALUE);             double arg2 = double.Parse(t2.VALUE);             double power = Math.Pow(arg1,arg2);              return CreateToken(TokenType.Value, power.ToString());         }//end Power         #endregion          public void Entry()         {             char[] equation = new char[1];             while (true)             {                 Array.Clear(equation, 0, equation.Length);                 equation = Console.ReadLine().ToCharArray();                 ParseEquation(equation);                  foreach (var t in tokenQue)                 {                     Console.Write(t.VALUE + ", ");                 }                 Console.WriteLine();                  EvalEquation();                  if (tokenStack.Count > 0)                     Console.WriteLine(tokenStack.Pop().VALUE);                 else                     Console.WriteLine("Nothing returned");                  tokenStack.Clear();                 tokenQue.Clear();             }         }//end Entry          #region EvalFunctions         private void EvalEquation()         {             Token temp = null;              while (tokenQue.Count != 0)             {                 temp = tokenQue.Dequeue();                  if (temp.TYPE == TokenType.Value)                     tokenStack.Push(temp);                 else                     OpperationSwitch(temp);             }         }//end EvalEquation         private void OpperationSwitch(Token t)         {             Token ret = null;             if (tokenStack.Count >= 2)             {                 Token t2 = tokenStack.Pop();                 Token t1 = tokenStack.Pop();                  switch (t.VALUE)                 {                     case ("*"):                         ret = Multiplication(t1, t2);                         break;                     case ("/"):                         ret = Division(t1, t2);                         break;                     case ("+"):                         ret = Addition(t1, t2);                         break;                     case ("-"):                         ret = Subtract(t1, t2);                         break;                     case ("^"):                         ret = Power(t1, t2);                         break;                 }                  if (ret != null)                     tokenStack.Push(ret);             }             else             {                 Console.WriteLine("Error in OpperationSwitch");                 //error code             }         }//end OpperationSwitch         #endregion          #region ParserFunctions         private void ParseEquation(char[] equation)         {             for (int i = 0; i < equation.Length; i++)             {                 priorType = null;                 //Console.WriteLine("ParseEquation:= i: {0} ; Char: {1}", i, equation[i]);                 if (char.IsDigit(equation[i]) || equation[i] == '.')                 {                     //executes if # or .                     AddToBuffer(equation[i]);                 }                 else                 {                     //if buffer has data, create token, place in queue, clear buffer, and set prior type.                     if (bufferLoc != 0)                     {                         tokenQue.Enqueue(CreateToken(TokenType.Value, new string(buffer, 0, bufferLoc)));                         Array.Clear(buffer, 0, bufferLoc);                         bufferLoc = 0;                         priorType = TokenType.Value;                     }                     //handles operands                     OperationHandler(equation[i]);                 }//end else-if             }//end while              //creates a token of anything remaining in the buffer, and queues it             if (bufferLoc != 0)             {                 tokenQue.Enqueue(CreateToken(TokenType.Value, new string(buffer, 0, bufferLoc)));                 Array.Clear(buffer, 0, bufferLoc);                 bufferLoc = 0;             }              //moves anything remaining on the tokenStack to the que             while (tokenStack.Count > 0)             {                 Token temp = tokenStack.Pop();                  if (temp.VALUE == "(")                 {                     //will only run in case of unpaired ()                     Console.WriteLine("Error with '(' in ParseEquation");                     //error code                 }                 tokenQue.Enqueue(temp);             }         }//end ParseEquation         private void OperationHandler(char opp)         {             if (opp == ')')             {                 //runs if the opp is )                 //Console.WriteLine("Entering ')' section of OperationHandler");                 Token temp = null;                 bool found = false;                  //cycles until the most recent ( is found. If not found, error.                 while (tokenStack.Count != 0)                 {                     temp = tokenStack.Pop();                     if (temp.VALUE == "(")                     {                         found = true;                         return;                     }                     else                     {                         tokenQue.Enqueue(temp);                     }                 }                  if (!found)                 {                     Console.WriteLine("Error with '(' section of OperationHandler");                     //error code                 }             }             else             {                 Token temp = CreateToken(TokenType.Operand, opp.ToString());                  //creates a multiplication incase of implicite multiplication. Ex: 5(4) => 5*4                 if (opp == '(' && priorType == TokenType.Value)                 {                     //Console.WriteLine("Creating a multiplication");                     tokenStack.Push(CreateToken(TokenType.Operand, "*"));                 }                  if (tokenStack.Count == 0)                 {                     //runs if stack is empty                     tokenStack.Push(temp);                 }                 else                 {                     OrderOfOpp(temp);                 }             }         }//end OperationHandler         private void OrderOfOpp(Token t)         {             string tempVal = null;             Dictionary<string, int> oppDic = new Dictionary<string, int>() {{"(",4 }, {"^",3},{"*",2},{"/",2},{"+",1},{"-",1}};             bool done = false;              while (!done || tokenStack.Count == 0)             {                 tempVal = tokenStack.Peek().VALUE;                  if (tempVal == "(")                 {                     //if most recent push to stack was (, auto push t to stack                     tokenStack.Push(t);                     done = true;                 }                 else                 {                     if (oppDic[t.VALUE] >= oppDic[tempVal])                     {                         //if the t token has a higher precident then the tempVal (Obtained from peek), pushes t to que                         tokenStack.Push(t);                         done = true;                     }                     else                     {                         //if the tempVal has a higher precident then pop and enqueue                         tokenQue.Enqueue(tokenStack.Pop());                     }                 }                  if (tokenStack.Count == 0)                 {                     //if stack is empty, push to stack                     tokenStack.Push(t);                     done = true;                 }             }//end while              if (!done)             {                 Console.WriteLine("Error in OrderOfOpp");                 //error code             }         }//end OrderOfOpp         #endregion          #region HelperFunctions         private void AddToBuffer(char add)         {             buffer[bufferLoc] = add;             bufferLoc++;         }//end AddToBuffer         private Token CreateToken(TokenType type, string value)         {             return new Token(type, value);         }//end CreateToken         #endregion     } } 
        

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

Una cosa, usando un scheduleWithFixedDelay8 simplificará su traducción de la fórmula analizada a los cálculos reales:

  scheduleWithFixedDelay9  

El cálculo se convierte en una simple mirada del diccionario con el operador apropiado:

  scheduleAtFixedRate0  
 

One thing, using a Dictionary<char, Func<double, double, double>> will simplify your translation from the parsed formula to the actual calculations:

public class Calculator {      public static  readonly  Dictionary<char, Func<double, double, double>> functions = new Dictionary<char, Func<double, double, double>>()         {             {'+',new Func<double,double,double>(Add)},             {'-', new Func<double,double,double>(Subtract)},             {'/',new Func<double,double,double>(Divide)},             {'*',new Func<double,double,double>(Multiply)}         };      static double Add(double num1, double num2)     {         return num1 + num2;     }     static double Subtract(double num1, double num2)     {         return num1 - num2;     }     static double Multiply(double num1, double num2)     {         return num1 * num2;     }     static double Divide(double num1, double num2)     {         return num1 / num2;     } } 

The calculation becomes a simple look up of the dictionary with the appropriate operator:

char operation = '+'; double num1 = 1; double num2 = 2; double newresult = Calculator.functions[operation](num1, num2); 
 
 
 
 

Relacionados problema

8  Codewars Evaluador de expresión matemática  ( Codewars mathematical expresion evaluator ) 
Recientemente escribí el siguiente código para un Codewars.com Kata para evaluar las expresiones matemáticas . He estado escribiendo Ruby durante años, pero ...

1  Evaluando una expresión aritmética de un árbol binario  ( Evaluating an arithmetic expression from a binary tree ) 
Digamos que tengo un árbol binario que se ve + 2 * 5 8 He escrito una función para atravesar el inicio para resolverl...

5  Calculadora de derivados algebraica estándar  ( Standard algebraic derivative calculator ) 
Tuve alguna dificultad con este problema, así que estoy seguro de que hay una mejor manera. Aquí está la pregunta de SICP : ejercicio 2.58 Supongamos ...

3  Análisis de expresión (solo operadores aritméticos)  ( Expression parsing arithmetic operators only ) 
Como un proyecto de auto-aprendizaje, escribí un analizador de expresión utilizando el algoritmo de la derivación del patio en JavaScript. Es una parte más gr...

3  Calculadora de RPN de NASM  ( Nasm rpn calculator ) 
He estado aprendiendo ensamblaje en los últimos días, y he hecho una simple calculadora RPN. Aquí está la lógica principal del programa, excluyendo las func...

3  La calculadora recursiva basada en RPN-STACK necesita TuneUp  ( Rpn stack based recursive calculator needs tuneup ) 
Esta función toma una serie de cuerdas y números y la procesa recursivamente como un tipo de "programa de cálculo". La estructura se basa en la notación de po...

1  Parser Ecuación + Solver  ( Equation parser solver ) 
Aquí hay un analizador de la ecuación que acabo de escribir. Mi enfoque fue la legibilidad y la perspectiva de agregar nuevas características en el futuro. Co...

2  Expresión de infijo (con números negativos) a Postfix  ( Infix expression with negative numbers to postfix ) 
Estoy escribiendo una clase para evaluar una expresión aritmética, ya que ahora mi clase puede convertir una expresión de infijo en PostFix, todavía no admite...

6  Programa de Convertidor de Infix a Postfix  ( Infix to postfix converter program ) 
Esta es mi tarea. Amablemente ayúdame a verificarlo? Las instrucciones son: Implementar una expresión de infIX en el convertidor de expresión postfix. De...

2  Verificación de expresiones matemáticas  ( Verifying mathematical expressions ) 
Esta es una parte de mi programa de calculadora. Tengo que verificar si la entrada ingresada por el usuario es una expresión matemática válida. El primer prog...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos