计算数学表达式

数学表示试如:“2+(3/5+log(10)+exp(30)) + (5 +4/(-6))”

模型:

数学公式分为几个元素,

操作数  如:2 操作符 如:+ - * / 表达式:如(5 +4/(-6)) 或者数学方法log(10)

其实整个公式是一个表达式:

调用方式:

string mathexpstr = "2+5*5/6*30";
CalculaterExpression cc = new CalculaterExpression();
decimal result = cc.Calculate(mathexpstr);

以下是代码:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Reflection;
  5 using System.Text;
  6 using System.Threading.Tasks;
  7
  8 namespace Calculate
  9 {
 10     /******************************************************
 11      *
 12      * Author: zgtian
 13      * Data: 2016/04/08
 14      *
 15      * ***************************************************/
 16
 17
 18
 19     /// <summary>
 20     /// 表达式中负数必须用()括起来。比如 -1+2 修改为(-1)+2 在比如3/-2 改为 3/(-2),
 21     /// 只支持单参数数学函数 比如log(200),暂不支持多参函数 比如 Atan2(a1,a2),
 22     /// 例外:默认ln=log10(number) pow=pow(e,number) e=exp(1)
 23     /// </summary>
 24     public class CalculaterExpression
 25     {
 26         public decimal Calculate(string expressionString)
 27         {
 28             Expression exp = ConvertStringToExpressionObject(expressionString);
 29             return Calculate(exp);
 30         }
 31
 32         /// <summary>
 33         /// 把字符串表达式转换成表达式类对象
 34         /// </summary>
 35         /// <param name="expressionString"></param>
 36         /// <returns></returns>
 37         private Expression ConvertStringToExpressionObject(string expressionString)
 38         {
 39             char[] chs = expressionString.ToCharArray();
 40             string str = expressionString.Substring(0, 1);
 41             int startIndex = 0;
 42             CharType preType = CharType.Unknown;
 43             Expression expression = new Expression();
 44
 45             for (int i = 0; i < chs.Length; i++)
 46             {
 47                 CharType currentCharType = GetCharType(chs[i]);
 48                 if (currentCharType != preType)
 49                 {
 50                     if (preType == CharType.NUMBER)
 51                     {
 52                         str = expressionString.Substring(startIndex, i - startIndex);
 53                         Decimal number = 0;
 54                         decimal.TryParse(str, out number);
 55                         expression.Operands.Add(number);
 56                         startIndex = i;
 57                         preType = currentCharType;
 58                     }
 59                     else if (!(preType == CharType.CHAR && currentCharType == CharType.LeftBracket))
 60                     {
 61                         startIndex = i;
 62                         preType = currentCharType;
 63                     }
 64                 }
 65
 66                 switch (currentCharType)
 67                 {
 68                     case CharType.CHAR:
 69                         {
 70                             if (preType != CharType.CHAR)
 71                             {
 72                                 startIndex = i;
 73                                 preType = currentCharType;
 74                             }
 75                         }
 76                         break;
 77                     case CharType.ADD:
 78                         {
 79                             expression.Operators.Add(CalcOperator.ADD);
 80                         }
 81                         break;
 82                     case CharType.SUBTRACT:
 83                         {
 84                             expression.Operators.Add(CalcOperator.SUBTRACT);
 85                         }
 86                         break;
 87                     case CharType.MULTIPLY:
 88                         {
 89                             expression.Operators.Add(CalcOperator.MULTIPLY);
 90                         }
 91                         break;
 92                     case CharType.DIVIDE:
 93                         {
 94                             expression.Operators.Add(CalcOperator.DIVIDE);
 95                         }
 96                         break;
 97                     case CharType.LeftBracket:
 98                         {
 99                             Expression childExpression = new Expression();
100                             childExpression.parentExpression = expression;
101                             expression.childExpression = childExpression;
102                             expression = childExpression;
103                             if (preType == CharType.CHAR)
104                             {
105                                 str = expressionString.Substring(startIndex, i - startIndex).ToLower();
106                                 str = str.Substring(0, 1).ToUpper() + str.Substring(1);
107                                 expression.FunctionName = str;
108                                 startIndex = i;
109                                 preType = currentCharType;
110                             }
111                         }
112                         break;
113                     case CharType.RightBracket:
114                         {
115                             expression.parentExpression.Operands.Add(expression);
116                             expression = expression.parentExpression;
117                         }
118                         break;
119                     case CharType.NUMBER:
120                         break;
121
122                 }
123                 if (i == chs.Length - 1)
124                 {
125                     if (currentCharType == CharType.NUMBER)
126                     {
127                         str = expressionString.Substring(startIndex);
128                         Decimal number = 0;
129                         decimal.TryParse(str, out number);
130                         expression.Operands.Add(number);
131                     }
132                 }
133             }
134             return expression;
135         }
136
137         /// <summary>
138         /// 计算表达式对象
139         /// </summary>
140         /// <param name="exp"></param>
141         /// <returns></returns>
142         private decimal Calculate(Expression exp)
143         {
144             decimal result = 0;
145             //先计算所有的表达式
146             for (int i = 0; i < exp.Operands.Count; i++)
147             {
148                 if (typeof(Expression).IsInstanceOfType(exp.Operands[i]))
149                 {
150                     exp.Operands[i] = Calculate((Expression)exp.Operands[i]);
151                 }
152             }
153
154             //计算乘除
155             for (int i = 0; i < exp.Operators.Count; i++)
156             {
157                 CalcOperator ope = exp.Operators[i];
158                 if (ope == CalcOperator.MULTIPLY)
159                 {
160                     exp.Operands[i] = (decimal)exp.Operands[i] * (decimal)exp.Operands[i + 1];
161                     exp.Operands.Remove(exp.Operands[i + 1]);
162                     exp.Operators.Remove(exp.Operators[i]);
163                     i--;
164                 }
165                 else if (ope == CalcOperator.DIVIDE)
166                 {
167                     exp.Operands[i] = (decimal)exp.Operands[i] / (decimal)exp.Operands[i + 1];
168                     exp.Operands.Remove(exp.Operands[i + 1]);
169                     exp.Operators.Remove(exp.Operators[i]);
170                     i--;
171                 }
172             }
173
174             //最后计算所有的加减法
175             for (int i = 0; i < exp.Operators.Count; i++)
176             {
177                 //负数比如(-1),如果此时的操作符不为-减号则解析错误
178                 if (exp.Operands.Count == 1)
179                 {
180                     exp.Operands[0] = 0 - (decimal)exp.Operands[0];
181                     break;
182                 }
183
184                 CalcOperator ope = exp.Operators[i];
185                 if (ope == CalcOperator.ADD)
186                 {
187                     exp.Operands[i] = (decimal)exp.Operands[i] + (decimal)exp.Operands[i + 1];
188                 }
189                 else if (ope == CalcOperator.SUBTRACT)
190                 {
191                     exp.Operands[i] = (decimal)exp.Operands[i] - (decimal)exp.Operands[i + 1];
192                 }
193                 else
194                 {
195                     throw new Exception("数学表达式解析错误,还有非加减的运算符:" + exp.Operands[i].ToString() + ope.ToString() + exp.Operands[i+1].ToString());
196                 }
197                 exp.Operands.Remove(exp.Operands[i + 1]);
198                 exp.Operators.Remove(exp.Operators[i]);
199                 i--;
200
201             }
202             result = (decimal)exp.Operands[0];
203             //如果表达式是数学方法,则调用数学方法
204             if (exp.Operators.Count == 0)
205             {
206                 if (!string.IsNullOrEmpty(exp.FunctionName))
207                 {
208                     result = CalcMathFunction(exp.FunctionName, (decimal)exp.Operands[0]);
209                     exp.FunctionName = null;
210                 }
211             }
212             return result;
213         }
214
215         /// <summary>
216         /// 数学方法,可以枚举出来,不必反射。
217         /// </summary>
218         /// <param name="functionName"></param>
219         /// <param name="value"></param>
220         /// <returns></returns>
221         private decimal CalcMathFunction(string functionName, decimal value)
222         {
223             try
224             {
225                 if (functionName.ToLower() == "pow")
226                 {
227                     //项目需求唯一的一个需要2个参数的数学方法且底数固定为e  Exp(1)
228                     return Convert.ToDecimal(Math.Pow(Math.Exp(1), (double)value));
229                 }
230
231                 if (functionName.ToLower() == "ln")
232                 {
233                     functionName = "Log10";
234                 }
235                 MethodInfo[] mathMethods = typeof(Math).GetMethods(BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public);
236                 MethodInfo actureMethod = null;
237                 for (int i = 0; i < mathMethods.Length; i++)
238                 {
239                     //只找一个参数的方法
240                     if (mathMethods[i].Name == functionName && mathMethods[i].GetParameters().Length==1)
241                     {
242                         actureMethod = mathMethods[i];
243                         break;
244                     }
245                 }
246
247                 Type parameterType = actureMethod.GetParameters()[0].ParameterType;
248                 string parameterTypeName = parameterType.Name;
249                 MethodInfo convertMethod = typeof(Convert).GetMethod("To" + parameterTypeName, new Type[] { typeof(decimal) });
250                 var parameter = convertMethod.Invoke(null, new object[] { value });
251                 var result = actureMethod.Invoke(null, new Object[] { parameter });
252                 return Convert.ToDecimal(result);
253             }
254             catch(Exception ex)
255             {
256                 throw new Exception("数学方法错误,方法名:" + functionName + ",参数:" + value + "," + ex.StackTrace);
257             }
258
259         }
260
261
262         private bool IsNumber(char c)
263         {
264             if ((c >= 48 && c <= 57) || c == 46)
265                 return true;
266             else
267                 return false;
268         }
269
270         private bool IsOperator(char c)
271         {
272             bool result = false;
273             switch (c)
274             {
275                 case ‘+‘:
276                 case ‘-‘:
277                 case ‘*‘:
278                 case ‘/‘:
279                     result = true;
280                     break;
281                 default:
282                     break;
283             }
284             return result;
285         }
286
287         private bool IsCharacter(char c)
288         {
289             if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122))
290             {
291                 return true;
292             }
293             return false;
294         }
295
296
297         private CharType GetCharType(char c)
298         {
299             switch (c)
300             {
301                 case ‘+‘:
302                     return CharType.ADD;
303                 case ‘-‘:
304                     return CharType.SUBTRACT;
305                 case ‘*‘:
306                     return CharType.MULTIPLY;
307                 case ‘/‘:
308                     return CharType.DIVIDE;
309                 default:
310                     break;
311             }
312             if (IsCharacter(c))
313                 return CharType.CHAR;
314             else if (IsNumber(c))
315                 return CharType.NUMBER;
316             else if (c == ‘(‘)
317                 return CharType.LeftBracket;
318             else if (c == ‘)‘)
319                 return CharType.RightBracket;
320             return CharType.Unknown;
321         }
322
323         private enum CharType
324         {
325            ADD,SUBTRACT,MULTIPLY,DIVIDE,NUMBER,CHAR,LeftBracket,RightBracket,Unknown
326         }
327
328
329     }
330
331     /// <summary>
332     /// 计算表达式 如()阔起来的、数学方法log(10)
333     /// </summary>
334     internal class Expression
335     {
336         private List<Object> operand = new List<object>();
337         private List<CalcOperator> operators = new List<CalcOperator>();
338         public Expression parentExpression = null;
339         public Expression childExpression = null;
340
341         /// <summary>
342         /// 只有当表达式为方法时才赋值
343         /// </summary>
344         public string FunctionName { get; set; }
345
346         public List<Object> Operands { get { return operand; } }
347         public List<CalcOperator> Operators { get { return operators; } }
348     }
349
350     /// <summary>
351     ///  操作符
352     /// </summary>
353     internal enum CalcOperator
354     {
355         ADD, SUBTRACT, MULTIPLY, DIVIDE
356     }
357
358
359 }

时间: 2024-10-15 10:59:14

计算数学表达式的相关文章

用栈计算数学表达式的值

用栈计算数学表达式的值 计算一个简单数学表达式(+ - * / ( ))的结果,有的这些符号的计算,常常需要看优先级来决定先算哪部分,计算机就是这个原理 两个概念: 中缀表达式(infix Expression):运算符写在两个操作数之间(运算符有一定的优先级,可以用圆括号改变运算顺序) 前/后缀表达式(prefix/postfix Expression):运算符写在两个表达式之前/之后(运算符没有优先级,没有括号,遇到运算符对它前面的两个操作数进行求值) 如中缀表达式“6*(8+7)/5”,换

Java 计算数学表达式(字符串解析求值工具)

Java字符串转换成算术表达式计算并输出结果,通过这个工具可以直接对字符串形式的算术表达式进行运算,并且使用非常简单. 这个工具中包含两个类 Calculator 和 ArithHelper Calculator 代码如下: import java.util.Collections; import java.util.Stack; /** * 算数表达式求值 * 直接调用Calculator的类方法conversion() * 传入算数表达式,将返回一个浮点值结果 * 如果计算过程错误,将返回一

js的eval()函数及其java实现(计算数学表达式)

概述:js的eval(str)可用于返回数学表达式的计算结果,但表达式的中括号"["和"]"表示连接符,不像算术里面的"先小括号,后中括号",花括号"{"不能被使用, 所以str的中括号和花括号都必须替换成对应的圆括号 java代码执行js: public static void main(String[] args) { ScriptEngineManager factory = new ScriptEngineManage

后缀表达式实战:Qt制作计算器

导言 相信学过数据结构的人都听说过后缀表达式,就是在学习栈的时候.可能也有很多人实现过这一算法,不过基本上也都是在控制台窗口里用用.相信大家也都用过计算器windows里面的calc.但是有没发现它只能单步计算,而不能一次计算一个表达式.后缀表达式就有了用武之地,可以一次性计算一整个个式子.科技要为生产服务,所以我就实际去做了一个依据后缀表达式的带有图形化界面的计算器. 什么是后缀表达式 后缀表达式又称逆波兰式,用于简化计算数学表达式,是计算器类软件开发的重要理论依据.这部分有两个要点: 中缀表

Java初学者:内建函数计算简单的数学表达式

这个应该在之前写的,忘记了,补上 这次我们说一下如何用java计算数学表达式的值,比如,我们要计算sin(pi/3) + cos(pi/6) + 5.6^3,怎么计算呢?这里我们需要用到java的math的内建函数,所谓内建函数,就是java已经给你的方法,你用就好了,有时候你需要自己导入包,但math却不用,java会自动导入,不用你手动导入.下面我们来看一下这个例子: 编译运行通过,没问题,这个很简单. Math.PI, 就是派了,Math.pow(z, 3),就是计算z的立方,Math.s

Sublime Text 常用的16 个 Sublime Text 快捷键

在我做了一次包含一些现场编码的演示后,一些观众问我是如何操作这么快.当然这里没有唯一的答案,答案是一堆简单的快捷键和大量的实践的组合.为了回应那些询问,我觉得有必要看看我每天想都不用想且使用的快捷键. 这里有一个15 16 个快捷键的精选列表(1个自定义快捷键),以gif动画展示,我每天使用.享受吧! (译者注:原文所列快捷键均为OS X环境,为了方便Windows和Linux环境童鞋的学习,译者将备注Windows和Linux下对应的快捷键) 选择 选择一个选中项的下一个匹配项 选择一个选中项

shell中各种括号的作用

小括号里是命令大括号是变量值   一.小括号,圆括号() 1.单小括号 () ①命令组.括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用.括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格. ②命令替换.等同于`cmd`,shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其标准输出,再将此输出放到原来命令.有些shell不支持,如tcsh. ③用于初始化数组.如:array=(a b

Shell脚本编程知识点总结及范例

 一:关于语言 1)编译性语言 编译型语言多半运作于底层,所处理的是字节.整数.浮点数或其它及其机器层经的对象.处理过程为:源程序--预处理--编译--汇编--链接,编译性语言为静态语言. 2)解释性语言 解释性语言读入程序代码并将其转化为内部的形式加以执行.处理过程:解释性(文本文件)-解释器去读取并执行.解释性语言为动态语言. 二:基础 变量类型 linux脚本中的变量不需要事先声明,而是直接定义使用(这点不同于其他高级编程语言中变量的使用)bash变量类型分为本地变量和环境变量. 本地变量

[ SHELL编程 ] shell中各种括号的使用方法

转载自:http://www.jb51.net/article/60326.htm 在这里我想说的是几种shell里的小括号,大括号结构和有括号的变量,命令的用法,如下:1.${var} 2.$(cmd) 3.()和{} 4.${var:-string},${var:+string},${var:=string},${var:?string} 5.$((exp)) 6.$(var%pattern),$(var%%pattern),$(var#pattern),$(var##pattern)现在分