算法概述#
变量定义: str-数学表达式
注:数学表达式的数值支持小数,符号只支持+ - * / ( )这几种。

计算原理::先将数学表达式的字符串(中缀表达式)转化为后缀表达式,然后计算后缀表达式的值。
注:为了运算结果的精度,运算过程中统一使用decimal类型的数据。

例:输入表达式"10*1.1/(2+8)+1.1+2.2-4.3",输出结果“0.1”。

算法代码(C#)#
代码如下:

//测试算法
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);Console.ReadLine();}
}/// <summary>
/// 计算数学表达式,基于后缀表达式的实现,可使用 + - * / ( ) 运算符
/// </summary>
class Calculator
{/// <summary>/// 计算数学表达式的值/// </summary>/// <param name="str">数学表达式</param>/// <returns></returns>public static decimal Calculate(string str){            try{Queue<string> queue = CreateRPN(str);decimal res = ParseRPN(queue);return res;}catch (OverflowException){throw new Exception("数据过大导致计算溢出");}catch (Exception){throw new Exception("无法计算错误的表达式");}}//生成后缀表达式private static Queue<string> CreateRPN(string str){//临时存储+ - * / ( 符号的栈Stack<char> stack = new Stack<char>();//存储后缀表达式的队列Queue<string> queue = new Queue<string>();for (int i = 0; i < str.Length; ){//如果是空格直接跳过if (str[i] == ' '){i++;continue;}else if ((str[i] >= '0' && str[i] <= '9') || (str[i] == '.')){//当前数decimal cur = 0;//小数标识bool isDecimal = false;//小数位数int num = 0;//特别要注意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] == ')'){//如果是 " )"那么需要弹出栈中的操作符号,并且把它加入到后缀表达式的队列中//一直到遇到符号栈中的 " ( " 为止while (stack.Count != 0 && stack.Peek() != '('){queue.Enqueue(stack.Pop() + "");}stack.Pop();i++;}else{//可能是 +  -  *  / 这些符号或者是左括号//这个时候需要判断符号栈中的栈顶元素与当前遍历到的字符的优先级的问题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;}//处理符号优先级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;}//解析后缀表达式private static decimal ParseRPN(Queue<string> queue){//结果栈Stack<decimal> res = new Stack<decimal>();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();}//基本运算单元private static decimal Calculate(decimal a, decimal b, String t){//计算if (t.Equals("+")){return a + b;}else if (t.Equals("-")){return a - b;}else if (t.Equals("*")){return a * b;}else{return a / b;}}
}

注:上面的代码简单扩展一下即可支持更复杂的运算符

算法实现#
中缀表达式转化为后缀表达式规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

例:中缀表达式“9+(3-1)3+10/2”转化为后缀表达式“9 3 1-3+ 10 2/+”。

后缀表达式的计算过程规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。

扩展:使用DataTable.Compute计算#
经评论区提醒,可以通过建条SQL语句,执行得到结果,SQL语句如下:

string strSQL="SELECT "+“10*1.1/(2+8)+1.1+2.2-4.3”;
注:SQL语句计算的方法我没去研究,仅供参考。

后来,我找到一种更简单的方法,使用DataTable.Compute计算数学表达式,代码如下:

//测试算法
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));  Console.ReadLine();
}/// <summary>
/// 计算数学表达式的值
/// </summary>
/// <param name="str">数学表达式</param>
/// <returns>计算结果</returns>
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("数据过大导致计算溢出");}catch (Exception){throw new Exception("无法计算错误的表达式");}
}

*注:DataTable.Compute计算的结果有decimal、double两种(已测试出的),个人猜测在decimal取值范围内的运算c#教程不会发生double运算的精度损失,但计算结果只能用范围较大的double类型表示。

目前来看,DataTable.Compute计算数学表达式的适用范围更全面一些。

参考资料#
堆栈实现计算数学表达式——CSDN
接触后缀表达式(逆波兰表示法)——Veda
将中缀表达式转化为后缀表达式——Veda
图解后缀表达式的计算过程——Veda
C#里如何计算一个表达式的值——CSDN

作者: time-flies

出处:https://www.cnblogs.com/timefiles/p/CalculatingMathematicalExpressions.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

签名:曾梦想仗剑天涯,后来工作太忙没去…

简单实用算法——计算数学表达式相关推荐

  1. 曲线聚类_机器学习入门必读:6种简单实用算法及学习曲线、思维导图

    来源:大数据DT 本文约3500字,建议阅读7分钟 本文为你介绍掌握机器领域知识的学习曲线.技术栈以及常用框架. [ 导读 ] 大部分的机器学习算法主要用来解决两类问题--分类问题和回归问题.在本文当 ...

  2. 机器学习入门必读:6种简单实用算法及学习曲线、思维导图

    来源:大数据DT 本文约3500字,建议阅读7分钟 本文为你介绍掌握机器领域知识的学习曲线.技术栈以及常用框架. [ 导读 ] 大部分的机器学习算法主要用来解决两类问题--分类问题和回归问题.在本文当 ...

  3. 简单实用算法——字节位序反转

    算法概述# 反转一个字节说的是位序反转,别将它和大端转小端混淆了,所谓大端和小端指的是字节序. 字节位序反转的实现vb.net教程算法很多,就是看看谁的算法效率更高了. 高手不是能写出最美丽的程序而是 ...

  4. ae绘图未指定错误怎么办_【教程】最全的ae表达式教学分享(实用!)表达式其实很简单...

    大部分人对ae表达式是望而却之,感觉很难,无从下手,网上的教程也是层次不齐,很难找到好的教程跟着学.于是呢,搜罗全网,整理了一份最全的最实用的ae表达式教学.也算是一个对自己的总结. 下面解决几个问题 ...

  5. 三维重建 3D reconstruction 有哪些实用算法?

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 三维重建 3D reconstruction 有哪些实用算法? https://www.zhihu.c ...

  6. python数据挖掘入门与实践-第一章-用最简单OneR算法对Iris植物分类

    前言: 这本书其实有配套代码的来着,但是有点坑的是,里面的代码对应的版本是有点旧的,用的时候会警告或者已经报错.甚至有些代码书里提了但是却没有写进去,要自己去摸索.我是每一章都跟着代码示例,把每一个步 ...

  7. 圆周率计算程序图计算机基础知识,沪教版(2019)高中信息技术 必修1 项目七 用计算机计算圆周率——设计简单数值数据算法 教案(3课时)...

    沪教版(2019)高中信息技术 必修1 项目七 用计算机计算圆周率--设计简单数值数据算法 教案(3课时) 项目七 用计算机计算圆周率 --设计简单数值数据算法 ■学习目标. (1)掌握数值数据的常用 ...

  8. cp 过程流程图模板_程序流程图有什么用?简单实用的流程图模板大全

    原标题:程序流程图有什么用?简单实用的流程图模板大全 程序流程图是什么呢?程序流程图就是用规定的符号描述一个程序中所需的各种操作或者判断的图表.程序流程图的设计是在处理流程图的基础上,通过对数据的整理 ...

  9. 机器学习中较为简单的算法有哪些?

    链接:https://www.zhihu.com/question/431924548 编辑:深度学习与计算机视觉 声明:仅做学术分享,侵删 作者:石塔西 https://www.zhihu.com/ ...

最新文章

  1. 全球及中国新鲜芒果制品市场投资份额与营销渠道分析报告2022版
  2. ccf a类期刊_喜报:我院2篇学生论文被CCFA类会议AAAI(2020)接收
  3. anasys hpc集群_这可能是最简单的并行方案,如何基于 AWS ParallelCluster 运行 ANSYS Fluent...
  4. MFC 问题集(4)CListCtrl
  5. 中国软件正版化的理想模型
  6. 【转】DICOM的常用Tag分类和说明!!!!
  7. 深入理解Python中的全局解释锁GIL
  8. 161011、oracle批量插入数据
  9. 华为高管“泄密”,华为P40 Pro外观定了!
  10. vs2010编译curl为static库及测试
  11. NLP是百度的核心技术之一
  12. Jvisualvm设置中文
  13. C/C++ isalpha、isalnum、islower、isupper函数详解
  14. php倒入百万行excel数据,PHP导入(百万级)Excel表格数据
  15. 迈微科讯 | 最新科技发展资讯
  16. 程序员复工后被裁,600万房21000房贷无力偿还,给年轻人3点忠告
  17. 分数指数幂计算机,分数指数幂教案
  18. 实现Windows XP自动登录的两种方法
  19. NLP: LDA主题模型
  20. 伪类和伪元素的区别是什么?

热门文章

  1. V3D/Vaa3D installation procedures in Windows(VS2013) V3D安装教程
  2. 【C#】int与int?
  3. 百度云解决迅雷一直寻找资源无法开始下载的问题
  4. BFT机器人带你走进智慧生活 ——探索遨博机器人i系列的多种应用
  5. 车载硬盘录像机-从芯片层面来谈嵌入式DVR的发展
  6. Freeline 的使用
  7. 笔记——51控制DS18B20温度控制篇章2之读取温度值
  8. 263前核心团队押注PC桌面广告 产品已运营半年
  9. Maya建模学习笔记
  10. 计算机常用计量单位,计量符号-计算机中的有些计量单位例如G、MB是表示什 – 手机爱问...