码迷,mamicode.com
首页 > 其他好文 > 详细

计算数学表达式

时间:2016-04-08 19:42:51      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:

数学表示试如:“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 }
View Code

 

计算数学表达式

标签:

原文地址:http://www.cnblogs.com/qingliangtea/p/5369672.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!