当前位置:网站首页>simple math formula calculation
simple math formula calculation
2022-08-09 04:03:00 【Liu-DaDa】
前言:
Calculate simple math formulas(加,减乘,除,括号)
方式一: C#提供方法
public class Test
{
/// <summary>
/// 计算公式
/// </summary>
public string express;
private void Compute()
{
// 计算结果
float result = 0;
try
{
float.TryParse(new System.Data.DataTable().Compute(express, string.Empty).ToString(), out result);
}
catch { }
}
}
方式二: 使用抽象语法树(AST)Split formula for calculation
需要理解ASTHow to break down the formula
拆分规则:
- Symbols outside parentheses take precedence within parentheses
- Symbol priority order : 加号 > 减号 > 乘号 > 除号
代码实现
using System.Collections.Generic;
/// <summary>
/// 节点
/// </summary>
public class Node
{
public Node left;
public Node right;
public SymbolType symbol;
public float value;
public Node()
{
left = null;
right = null;
symbol = SymbolType.None;
value = 0;
}
public float GetValue()
{
float result = 0;
switch (symbol)
{
case SymbolType.None:
result = value;
break;
case SymbolType.Add:
result = left.GetValue() + right.GetValue();
break;
case SymbolType.Sub:
result = left.GetValue() - right.GetValue();
break;
case SymbolType.Mult:
result = left.GetValue() * right.GetValue();
break;
case SymbolType.Div:
result = left.GetValue() / right.GetValue();
break;
}
return result;
}
}
/// <summary>
/// symbol enumeration
/// </summary>
public enum SymbolType
{
None,
Add,
Sub,
Mult,
Div
}
/// <summary>
/// 计算
/// </summary>
public class Compute
{
/// <summary>
/// symbols outside parentheses
/// </summary>
private SymbolType outSymbol = SymbolType.None;
/// <summary>
/// Symbols outside the parentheses correspond to indices
/// </summary>
private int outSymbolIndex = 0;
/// <summary>
/// Symbols in parentheses
/// </summary>
private SymbolType inSymbol = SymbolType.None;
/// <summary>
/// Symbols in parentheses correspond to indices
/// </summary>
private int inSymbolIndex = 0;
/// <summary>
/// Symbols in brackets correspond to levels
/// Each has a layer of parentheses,级别+1
/// The grades outside the brackets are all0
/// </summary>
private int inSymbolLevel = 0;
/// <summary>
/// 设置子节点
/// </summary>
/// <param name="express">公式</param>
/// <returns></returns>
public Node SetNode(string express)
{
// 节点
Node node = new Node();
float value = 0;
// Nodes are numbers
if (float.TryParse(express, out value))
{
node.symbol = SymbolType.None;
node.value = value;
}
else
{
int index = 0;
// Record the number of symbols outside the parentheses
int outBracketCount = 0;
// Last matching parenthesis(parenthesis end flag)
bool isLastBracket = false;
// Document the bracket level
inSymbolLevel = 0;
// The stack to store the left parenthesis
Stack<char> leftBracketStack = new Stack<char>();
foreach (var item in express)
{
index++;
if (item == '+' || item == '-' || item == '*' || item == '/' || item == '(' || item == '(' || item == ')' || item == ')')
{
isLastBracket = false;
// 匹配括号
switch (item)
{
case '(':
case '(':
// The left parenthesis is pushed onto the stack
leftBracketStack.Push(item);
break;
case ')':
case ')':
// When a closing bracket is encountered, pop it from the stack
leftBracketStack.Pop();
// Last matching parenthesis
if (leftBracketStack.Count == 0)
{
isLastBracket = true;
}
break;
default:
if (leftBracketStack.Count > 0)
{
// The lower the symbol level,越优先
// (1+(2-3))
// + 等级为1, - 等级为2
if (inSymbolLevel > leftBracketStack.Count)
{
inSymbol = SymbolType.None;
}
SetSymbol(item, index, false, leftBracketStack.Count);
}
break;
}
// 括号外
if (leftBracketStack.Count == 0 && isLastBracket == false)
{
outBracketCount++;
if (SetSymbol(item, index))
{
// 情况一: Addition outside parentheses takes precedence
// 直接结束
SetRoot(express, node);
break;
}
}
}
}
// 情况二: The outermost layer is the parentheses(a+...*b),outBracketCount为零的情况
// 情况三: Divide nodes according to the highest-priority symbol found
if (node.symbol == SymbolType.None)
{
SetRoot(express, node, outBracketCount == 0);
}
}
return node;
}
/// <summary>
/// 设置根节点
/// </summary>
/// <param name="express">The formula that needs to be parsed</param>
/// <param name="node">当前节点</param>
/// <param name="isBracket">有括号</param>
private void SetRoot(string express, Node node, bool isBracket = false)
{
// 根
// The root node is the symbol
node.symbol = isBracket ? inSymbol : outSymbol;
outSymbol = SymbolType.None;
inSymbol = SymbolType.None;
string tStr = string.Empty;
// The root node is a number
if (node.symbol == SymbolType.None)
{
// 根节点
// 移除括号(-1)
tStr = express.Substring(1, express.Length - 2);
float.TryParse(tStr, out node.value);
}
else
{
// 去除最外层括号,如果有
int tempIndex = isBracket ? inSymbolIndex : outSymbolIndex;
// 左节点
int index = 0;
if (isBracket)
{
index = 1;
}
tStr = express.Substring(index, tempIndex - index - 1);
node.left = SetNode(tStr);
// 右节点
tStr = express.Substring(tempIndex);
if (isBracket)
{
tStr = tStr.Remove(tStr.Length - 1);
}
node.right = SetNode(tStr);
}
}
/// <summary>
/// 同级别下
/// 符号优先级+ > - > * > /
/// </summary>
/// <param name="symbol">符号</param>
/// <param name="index">符号索引</param>
/// <param name="isOutSymbol">symbols outside parentheses</param>
/// <param name="inSymbolLevel">Symbol level in parentheses</param>
/// <returns></returns>
private bool SetSymbol(char symbol, int index, bool isOutSymbol = true, int inSymbolLevel = 0)
{
// 符号开头的情况,不予解析
// -1 + 2
// (-1 + 2)
if ((isOutSymbol && index == 1) || (isOutSymbol == false && index == 2))
{
return false;
}
switch (symbol)
{
case '+':
if (isOutSymbol)
{
outSymbol = SymbolType.Add;
outSymbolIndex = index;
}
else
{
if (inSymbol == SymbolType.None || this.inSymbolLevel >= inSymbolLevel)
{
inSymbol = SymbolType.Add;
inSymbolIndex = index;
this.inSymbolLevel = inSymbolLevel;
}
}
break;
case '-':
if (isOutSymbol)
{
if (outSymbol == SymbolType.None || outSymbol == SymbolType.Mult || outSymbol == SymbolType.Div)
{
outSymbol = SymbolType.Sub;
outSymbolIndex = index;
}
}
else
{
if (inSymbol == SymbolType.None || inSymbol == SymbolType.Mult || inSymbol == SymbolType.Div)
{
inSymbol = SymbolType.Sub;
inSymbolIndex = index;
this.inSymbolLevel = inSymbolLevel;
}
}
break;
case '*':
if (isOutSymbol)
{
if (outSymbol == SymbolType.None || outSymbol == SymbolType.Div)
{
outSymbol = SymbolType.Mult;
outSymbolIndex = index;
}
}
else
{
if (inSymbol == SymbolType.None || inSymbol == SymbolType.Div)
{
inSymbol = SymbolType.Mult;
inSymbolIndex = index;
this.inSymbolLevel = inSymbolLevel;
}
}
break;
case '/':
if (isOutSymbol)
{
if (outSymbol == SymbolType.None)
{
outSymbol = SymbolType.Div;
outSymbolIndex = index;
}
}
else
{
if (inSymbol == SymbolType.None)
{
inSymbol = SymbolType.Div;
inSymbolIndex = index;
this.inSymbolLevel = inSymbolLevel;
}
}
break;
}
return outSymbol == SymbolType.Add;
}
}
简单使用
public class Test
{
/// <summary>
/// 计算公式
/// </summary>
public string express;
private void Compute()
{
// 计算结果
float result = 0;
try
{
result = new Compute().SetNode(express).GetValue();
}
catch { }
}
}
边栏推荐
- gopacket源码分析
- leetcode 5709. 最大升序子数组和
- 技术分享 | 如何模拟真实使用场景?mock 技术来帮你
- el-popover 内嵌 el-table 后位置错位 乱飘 解决方案
- 查询某时间段获得的积分总积分的大小进行排序
- 数据库指标是怎么个意思
- 欧拉22.02系统 mysql5.7 arm版本的安装包, 哪里能下载到?
- 5.索引优化实战
- A separate machine is connected to the spark cluster of cdh, and the task is submitted remotely (absolutely successful, I have tested it n times)
- leetcode 5724. 绝对差值和
猜你喜欢
随机推荐
盘点检索任务中的损失函数
PhotoShop软件笔记
【图形学】20 基础纹理(一、单张纹理)
EventLoop同步异步,宏任务微任务笔记
笔记本电脑重装系统后开机蓝屏要怎么办
松柏集(浮窗思)
网络设置、ssh服务
From brute force recursion to dynamic programming leetcode Question 62: Different paths
荣耀路由(WS831)做无线中继时LAN网段与WAN网段冲突解决方法
33 基本统计知识——单项非参数检验
MutationObserver接口(一) 基本用法
driftingblues靶机wp
MKNetworkKit replacing domain name wrong solution
OpenCV相机标定完全指南(有手就行)
记录一次腾讯实习投递经历(一)
gopacket源码分析
了解CV和RoboMaster视觉组(五)图像处理中使用的滤波器
How to resolve the conflict between LAN segment and WAN segment when Honor router (WS831) is used as wireless relay
"The Sword Offer" Problem Solution - week1 (continuously updated)
Detailed explanation of Oracle's windowing function