Time：2021-12-30

# Algorithm overview

Variable definition:STR mathematical expression
Note: numerical value of mathematical expressionSupport decimal, symbolOnly + – * / ()These.

Calculation principle:: first convert the string of mathematical expression (infix expression) toPostfix Expression , and then evaluate the value of the suffix expression.
Note: in order to improve the accuracy of calculation results, it is used uniformly in the calculation processdecimalType of data.

Example: enter the expression “10 * 1.1 / (2 + 8) + 1.1 + 2.2-4.3” and output the result “0.1”.

# Algorithm code (c#)

The code is as follows:

``````//Test algorithm
class Program
{
static void Main(string[] args)
{
string str = "10*1.1/(2+8)+1.1+2.2-4.3";
decimal res = Calculator.Calculate(str);
Console.WriteLine(str+"="+res);
}
}

///
///Calculate the mathematical expression. Based on the implementation of suffix expression, you can use + - * / () operator
///
class Calculator
{
///
///Calculates the value of a mathematical expression
///
///Mathematical expression
///
public static decimal Calculate(string str)
{
try
{
Queue queue = CreateRPN(str);
decimal res = ParseRPN(queue);
return res;
}
catch (OverflowException)
{
Throw new exception ("calculation overflow caused by too large data");
}
catch (Exception)
{
Throw new exception ("unable to evaluate the wrong expression");
}

}

//Generate suffix expression
private static Queue CreateRPN(string str)
{
//Stack of temporary storage + - * / (symbols)
Stack stack = new Stack();
//A queue that stores suffix expressions
Queue queue = new Queue();
for (int i = 0; i < str.Length; )
{
//If it is a space, skip directly
if (str[i] == ' ')
{
i++;
continue;
}
else if ((str[i] >= '0' && str[i] <= '9') || (str[i] == '.'))
{
//Current number
decimal cur = 0;
//Decimal identification
bool isDecimal = false;
//Decimal places
int num = 0;
//Pay special attention to the condition I < s.length
while (i < str.Length && ((str[i] >= '0' && str[i] <= '9') || (str[i] == '.')))
{
if (str[i] == '.')
{
isDecimal = true;
}
else
{
if (!isDecimal)
{
cur = cur * 10 + str[i] - '0';
}
else
{
num++;
cur = cur + ((decimal)(str[i] - '0')) / (decimal)(Math.Pow(10, num));
}
}
i++;
}
queue.Enqueue(cur.ToString());
}
else if (str[i] == ')')
{
//If it is ")", you need to pop up the operation symbol in the stack and add it to the queue of suffix expression
//Until "(" in the symbol stack is encountered
while (stack.Count != 0 && stack.Peek() != '(')
{
queue.Enqueue(stack.Pop() + "");
}
stack.Pop();
i++;
}
else
{
//It may be + - * / these symbols or left parentheses
//At this time, you need to determine the priority of the top element of the symbol stack and the currently traversed character
while (stack.Count != 0 && Compare(stack.Peek(), str[i]) < 0)
{
queue.Enqueue(stack.Pop() + "");
}
stack.Push(str[i]);
i++;
}
}
while (stack.Count != 0)
{
queue.Enqueue(stack.Pop() + "");
}
return queue;
}

//Processing symbol priority
private static int Compare(char peek, char c)
{
if (peek == '(' || c == '(') return 1;
if (c == '+' || c == '-') return -1;
if (c == '*' && (peek == '*' || peek == '/')) return -1;
if (c == '/' && (peek == '*' || peek == '/')) return -1;
return 1;
}

//Resolve suffix expression
private static decimal ParseRPN(Queue queue)
{
//Result stack
Stack res = new Stack();
while (queue.Count != 0)
{
String t = queue.Dequeue();
if (t.Equals("+") || t.Equals("-") || t.Equals("*") || t.Equals("/"))
{
decimal a = res.Pop();
decimal b = res.Pop();
decimal result = Calculate(b, a, t);
res.Push(result);
}
else
{
res.Push(decimal.Parse(t));
}
}
return res.Pop();
}

//Basic arithmetic unit
private static decimal Calculate(decimal a, decimal b, String t)
{
//Calculate
if (t.Equals("+"))
{
return a + b;
}
else if (t.Equals("-"))
{
return a - b;
}
else if (t.Equals("*"))
{
return a * b;
}
else
{
return a / b;
}
}
}``````

Note: the above code can be extended to support more complex operators

# Algorithm implementation

Rules for converting infix expression to suffix expression: traverse each number and symbol of infix expression from left to right. If it is a number, it will be output, that is, it will become a part of suffix expression; If it is a symbol, it is judged that its priority with the top symbol is the right bracket or the priority is lower than the top symbol (multiplication and division priority plus and minus), then the top elements of the stack are found and output in turn, and the current symbol is put on the stack until the suffix expression is finally output.

Example: infix expression “9 + (3-1)3 + 10 / 2 “is converted to suffix expression” 9 3 1-3 “+ 10 2/+”。

Rules for evaluating suffix expressions: traverse each number and symbol of the expression from left to right. If it is a number, it will enter the stack. If it is a symbol, it will take the two numbers at the top of the stack out of the stack for operation. The operation result will enter the stack until the final result is obtained.

# Extension: use datatable Compute calculation

A simpler way,Use datatable Compute computes mathematical expressions, the code is as follows:

``````//Test algorithm
static void Main(string[] args)
{
Console.WriteLine(Calculate("10*1.1/(2+8)+1.1+2.2-4.3"));
Console.WriteLine(Calculate(double.MaxValue+"+"+double.MaxValue));
}

///
///Calculates the value of a mathematical expression
///
///Mathematical expression
///Calculation results
private static double Calculate(string str)
{
try
{
DataTable dt = new DataTable();
double result = double.Parse(dt.Compute(str, "").ToString());
return result;
}
catch (OverflowException)
{
Throw new exception ("calculation overflow caused by too large data");
}
catch (Exception)
{
Throw new exception ("unable to evaluate the wrong expression");
}
}``````

*Note:DataTable. The results of compute calculation include decimal and double (tested), I guess that the precision loss of double operation will not occur in the operation within the decimal value range, but the calculation result can only be represented by the double type with a large range.

For now,DataTable. Compute computes mathematical expressions with a more comprehensive scope of application

# Extensions: evaluating mathematical expressions using SQL

Can passExecute the SQL statement to get the result of the mathematical expression, the SQL statement is as follows:

``string strSQL="SELECT "+"10*1.1/(2+8)+1.1+2.2-4.3";``

The benefits of using SQL statements areIt can calculate mathematical expressions containing more advanced operations such as square and square, the most simple and convenient is to useSQLite (no database communication overhead)Database to calculate the mathematical expression. The code is as follows:

``````///
///Evaluates the given expression
///
///Expression
///
public static object SQLiteCompute(string expr)
{
expr = expr.Replace("/", "*1.0/");
expr = expr.Replace("[", "(");
expr = expr.Replace("]", ")");
expr = expr.Replace("{", "(");
expr = expr.Replace("}", ")");

string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DataBass");
if (!Directory.Exists(path)) Directory.CreateDirectory(path);

string connStr = Path.Combine(path, "ComputeEngine.db");
if (!File.Exists(connStr)) File.Create(connStr).Close();

using (SQLiteConnection conn = new SQLiteConnection("Data Source=" + connStr))
{
if (conn.State != ConnectionState.Open)
conn.Open();
var cmd = new SQLiteCommand();

cmd.Parameters.Clear();
cmd.Connection = conn;
cmd.CommandText = "SELECT " + expr;
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 30;
return cmd.ExecuteScalar();
}
}``````

usage method:

``````static void Main(string[] args)
{
string result = SQLiteCompute("sqrt(1+2)/[4+(1+1)/3]").ToString();
Console.WriteLine(result);

}``````

Calculation results:

``0.371153744479045``

For information about using SQLite database, you can refer toUse of SQLite and tool class in C #

# reference material

## Redis featured Q & A

Redis data type type brief introduction characteristic scene String (string) Binary security It can contain any data, such as JPG pictures or serialized objects. One key can store up to 512M It can be used to do the simplest data. It can cache a simple string or a JSON format string. The implementation of redis […]