分享Delphi实现数学表达式的计算(逆波兰式法)-四则运算解析

tjs_125 tjs_125 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
http://www.cnblogs.com/tangqs/archive/2011/11/03/2234715.html
众所周知,计算机处理表达式的难点在于括号的处理,在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法。按此方法,每一运算符都置于其运算对象之后,故称为后缀表示。如a+b表达为ab+。这种后缀表达式非常方便去掉运算符优先级的影响与括号,甚至是单目运算符:
示例说明:
1. a*b+c*(d+e) 逆波兰表达式: ab*cde+*+
2. -a+-b*+c 逆波兰表达式: a~b~c@*+
3.a-(-(b-c)) 逆波兰表达式: abc-~ -
预处理:
-(负号)处理:用~代替
+(正号)处理:用@代替,或者将其在字符串中删除
数学自然常数 e 与圆周率 pi 的用 (2.718281828459045) 与 (3.1415926535897932384) 代替(包含前后的括弧)

那么计算机怎样通过后缀式来进行运算呢?这里首先假设读取分析表达式的准备工作都已经做好了,那么首先需要做的是把表达式转换成后缀式,也就是逆波兰表达式的构建过程。
构建器由两个主要组件组成,一个是目标表达式的存储器,另一个是一个符号栈。与源表达式的扫描顺序一样,存储器是从左向右储存数据的,而符号栈则遵守后进先出的原则:
* 读入一个数据(数值与函数名非单个字符,需要做判断处理)
1. 如果是左单目运算符或者函数名,直接入符号栈;比如 正负号 ~ @ max sin
2. 如果是右单目运算符,直接入存储器栈;比如 阶乘!与百分号%
3. 如果是运输量,则直接写入存储器;检查符号栈顶是否有单目运算符,有的话则全部出栈,并写入存储器;
4. 如果是左括号"(",则直接入符号栈;
5. 如果是右括号")",则弹出符号栈数据,写入存储器,一直到左括号弹出,再检查栈顶是否为左单目运算符或者函数名,是的话继续弹出,直到遇到双目运算符;
6. 如果是普通运算符,则与栈顶符号比较优先级,若大于栈顶优先级,则入栈;否则弹出栈顶符号并写入存储器,直到栈顶符号的运算优先级较小为止;
7.如果是函数参数的连接逗号“,”时,则弹出符号栈数据,直到遇到左括弧 ( 或者逗号,为止,再将逗号,入符号栈;
8.如果是结束符(表示表达式已全部读完),则符号栈全部弹出并写入存储器,否则读取数据进入下个过程;
此外还有一些处理的技巧,比如定义一个优先级最低的运算符作为表达式结束的标志(用#标示,添加在表达式结尾处),在符号栈里首先加入一个结束标志,那么表达式读完时则自动弹出栈中所有符号,并写入存储器结尾表示成功。
接下来是计算的过程。计算的时候除了刚才构建的数据外,还需要另外一个计算中间值存储栈。
1、首先是从左至右扫描数据段,如果读出的是数据则压入计算中间值存储栈;
2、遇到单目运算符号就从计算中间值存储栈弹出一个数据进行运算,再把结果压回计算中间值存储栈;
3、遇到双目运算符号就从计算中间值存储栈弹出两个数据进行运算,再把结果压回计算中间值存储栈;这里需要注意减法与除法的计算顺序是第一次弹出的值作为减数和除数,第二次弹出的值作为被减数和被除数。
4、遇到逗号,就从计算中间值存储栈弹出两个数据用“,”连接起来直接将数值字符串压入计算中间值存储栈,不做计算。比如 12 13 , 压入13,12
5、遇到函数,弹出计算中间值存储栈的相关数据调用函数进行计算;
这样,返回结果就是栈中唯一的数据,我们完成了逆波兰表达式的全部计算过程。
最后还有一点就是检查给点表达式是否正确,就是下面的
function CheckCalcExp(const ExpT: string; var AInfo: string): boolean;
这样保证计算不会出错,具体见代码。
/* 表达式计算 */
/* 调用方式:CalcExp('1+max(0.5,sin(1))+sum(1,2^3,mod(5,3))', res, infoStr) */
/* 带符号参数调用方法,先调用符号定义AddSignParam,再调用 CalcExp: */
/* AddSignParam(['a','s'], [1, 0.5]); 或者 AddSignParam('a=1,s=0.5') */
/* CalcExp('1+a+sin(s)', res, infoStr) */
/* 其中res存储计算结果,为double型;infoStr存储计算时的提示信息,为string */
表达式计算器 V2.3 支持以下功能:
1、四则运算 + - * / 、括弧()、正负(+ -)
2、百分数 %、求幂 ^ 、整数阶乘 ! (1 至 150)
3、参数符号计算,示例:a+b @@a=1,b=2 结算结果为3
用@@表示表达式中定义符号的值
4、常数e、圆周率PI
5、丰富的函数功能:
统计函数: max,min,sum,avg,stddev 标准偏差,均支持多参数
三角函数: sin,cos,tan,arcsin,arccos,arctan
degrad(60) 角度转弧度
raddeg(3.14) 弧度转角度
costh(a,b,c) 余弦定理 cosC)
指数对数函数:sqrt,power(x,y),abs,exp,log2,log10,logN(a,N),ln
数据处理函数:int(x),trunc(x) 取整
frac(x) 取小数部分
round(x) 四舍五入取整
roundto(x,-1) 保留一位小数
mod(M,N) 求模
几何面积函数:s_tria(a,b,c) 三角形面积
s_circ(r) 圆形面积
s_elli(a,b) 椭圆面积
s_rect(a,b) 矩形面积
s_poly(a,n) 正多边形面积
平面几何函数:pdisplanes(x1,y1,x2,y2) 平面两点距离
pdisspace(x1,y1,z1,x2,y2,z2) 空间两点
p_line(x0,y0, A, B, C) 平面点到线距离
p_planes(x0,y0,z0 A, B, C, D)空间点到面距离
数列求和: sn(a1, d, n) 等差数列前n项和
sqn(a1, q, n) 等比数列前n项和
个税计算函数:intax(x), arcintax(x) 个税反算
6 、历史计算记录,双击计算记录可重新修改计算
示例: sin(1)+(-2+(3-4))*20% , e^63+PI , 15! , log2(max(2,3))
注: 运算符必须为半角格式,三角函为弧度,输入可用空格间隔
代码太大,大家可以到下面网站下载:
http://www.cnblogs.com/tangqs/archive/2011/11/03/2234715.html
...全文

相关推荐

2026安卓开发从零实战指南:环境搭建、核心基础与避坑干货(适配新版Android_Studio).pdf

2026安卓开发从零实战指南:环境搭建、核心基础与避坑干货(适配新版Android_Studio).pdf

彼岸交流群

如何实现科研成果转化率的有效提升与技术市场精准对接?.docx

如何实现科研成果转化率的有效提升与技术市场精准对接?

BIZKEEN

基于PID控制的ABS汽车防抱死制动系统、车轮滑移率+最优滑移率Carsim和Simulink联合仿真(带参考文献)

内容概要:本文档系统研究了基于PID控制的ABS汽车防抱死制动系统,聚焦于车轮滑移率与最优滑移率的动态控制问题,采用Carsim与Simulink联合仿真平台构建高精度车辆动力学模型与控制系统。研究详细阐述了ABS的工作机理,通过设计PID控制器实时调节制动压力,确保车轮滑移率稳定在最优区间,从而最大化轮胎与路面间的摩擦力,提升制动效能与行车安全性。文档涵盖了完整的建模流程、控制策略设计、仿真验证方法及参数整定过程,并提供了详实的参考文献支持,增强了研究的可复现性与工程应用价值。; 适合人群:具备车辆工程、自动化或控制理论等相关专业背景,熟悉MATLAB/Simulink与Carsim仿真环境的研究生、科研人员及汽车行业技术研发工程师。; 使用场景及目标:①用于ABS控制算法的教学讲解与科研实验;②支撑车辆制动性能优化、主动安全系统开发等实际工程应用;③为相关学术论文撰写、课题复现与技术创新提供理论依据与技术参考。; 阅读建议:建议读者结合所提供的仿真模型与参考文献,逐步运行并调试代码,重点关注滑移率计算逻辑、PID参数整定方法及联合仿真的数据交互机制,同时可尝试引入模糊控制、自适应控制等先进算法进行对比分析,以深入掌握ABS系统的控制精髓与优化路径。

荔枝科研社

高校如何利用技术转移数据分析优化成果转化路径?.docx

科易网基于40亿+科创知识图谱数据库,深度探索AI技术在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,研究科技创新领域的AI+数智化解决方案,推动科技创新与产业创新智能化发展。

BIZKEEN

Python3 for-else特殊语法

Python是唯一自带for-else语法的主流语言,新手极易忽略。else代码块仅在for循环正常遍历结束、未触发break时执行。如果循环内部通过break强制跳出,else代码会直接跳过。典型业务场景:遍历列表查找目标数据,找到就break,找不到执行else输出未查询到。对比传统写法,无需额外定义标记变量,精简代码行数。需要区分else和continue关系:continue仅跳过单次循环,不影响整体遍历,不会阻断else执行。日常开发搜索、匹配场景优先使用该语法,替代flag标记变量,减少冗余代码。 qqvqa.xilaohan.com qsvsnks.hbwsjyyz.com www.lvxianxing.cn jjvshj.kdd888.com www.gxqnm.com

2601_97221268
评论 48
收藏 已收藏
分享
返回顶部