表达式计算器项目设计文档
日期 版本号 修订说明 修订人 审核人 批准人
2012/7/27 V1.0
创建文档 李兵
2012/7/30 V1.2
修订 V1.0 的错误 李兵
1
第1章 项目概述
1.1 项目目标
本项目是一个自由函数计算器,当用户输入一个表达式程序能够根据表达式计算出相
应的结果,为用户提供一个简单易用,功能强大的计算服务。
1.2 项目简介
要求:写一个控制台程序,该程序实现输入一个表达式能够根据表达式计算出相应的
结果。
例如:例如:输入字符串"1+2*(3-4)/5=",输出结果:0.6
要求:
基本要求:能够对+ - * / 进行运算,能够对优先级进行运算和括号匹配运算。
扩展要求:
1. 支持多数据类型输入,如: 0x12F(十六进制)、 12FH(十六进制)、
234O(八进制) 、‘ F’(字符) 、0000 1111B(二进制)
2. 支持未知数赋值运算 如: x=3 则 3X+5=14
3. 支持常用函数运算 如: Log、 Ln、 sin、 sqrt 等;
4. 支持大数据计算;
5. 支持自定义运算符。
1.3 项目条件
编程语言:C++
开发平台:Windows
开发环境:Visual Studio 2010
1
第2章 系统设计
2.1 重要决策点及其理由
操作系统选择在 Windows 下开发,调试方便,开发效率高。开发完成之后要在
Linux(Ubuntu)下进行测试,保证能够跨系统运行。
编程语言选择 C++而不是 C,因为本自由函数计算器明显是在 PC 上使用,不用考虑向
嵌入式移植的问题,使用面向对象的设计方式,便于理解和程序架构,并且 C++中提供现
成的 STL 容器类,可以很方便的使用,并且稳定性高。
技术上,第一种方案是将命令、变量、函数、括号、无括号表达式分开处理,按从左
到右的顺序依次处理,每次只处理一种类型并将计算结果替换成字符串,然后进行下一类
型的处理,直至无括号表达式处理结束,输出结果。代码编写则按照自底向上的设计方法,
从右往左依次编写,这样顶层的处理就可以调用其需要的底层函数。
第二种实现方案是使用二叉树,根据表达式直接构建一个表达式树,根据优先级对二
叉树进行排序,然后从子节点开始计算,直至根节点,即使需要的结果。
第三种方案是将数学表达式转换为波兰表达法,然后按照前缀式或者或者后缀式的计
算规则,计算出最终结果。
三种方案,第一种方案逻辑上易于理解,最容易想到,但是需要多次扫描字符串来进
行解码,编程量较大。第二和第三种方案是比较成熟的解决方案,具有固定的计算顺序和
规则,不需要对表达式进行重复扫描来进行解码,并且经过初步翻译之后,不需要再考虑
括号和优先级,表达式的求值可以获得非常高的效率。
时间安排
8.13 之前完成三种方案的程序的编写
2.2 需求分析
实现基本的四则运算以及乘方运算和括号匹配
多种进制数字解析以及计算,默认是 10 进制,十六进制,0x 开头或 h 结;
十进制,无开头结尾或 d 结尾;八进制,o 结尾;二进制,b 结尾。
未知数赋值运算,使用结构体存储变量名和变量数值,并添加变量相关命
令。
常用函数计算,
sin、cos、tan、cot、asin、acos、log、log10,、exp、sqrt、pow 等。
大数据计算,使用 long long,long double 类型等处理数据,当数据依然超出
范围时,使用数据截断再拼合的方法进行处理。
自定义运算符,允许用户按照固定格式自定义运算符,并可以进行计算。
使用帮助,帮助系统可以本系统查看所有的命令以及命令的用法。
2.3 架构设计
整个系统分为三大模块,字符串输入模块,子字符串解析模块,按优先级计算模块。
其中字符串输入模块要求满足手动输入和文件输入。子字符串解析模块能够根据运算符将
字符串分割成子字符串,并分并分别识别命令、函数、变量、多种进制的数字字符串。按
2
优先级计算模块要能够根据数学上的优先级对表达式进行计算。
三种方案的字符串输入模块和子字符串解析模块都相同,但是按优先级计算模块不同。
2.4 详细设计
2.4.1 方案一
第一种方案的基本设计思路是将命令、用户自定义运算符、变量、函数、括号、无括
号表达式分开处理,按从左到右的顺序依次处理,每次只处理一种类型并将计算结果替换
成字符串,然后进行下一类型的处理,直至数学表达式处理结束,输出结果。思路简单,
但是需要多次扫描字符串进行解码,程序总体流程图 2。
允许同一行输入多个表达式或者命令,用空格分隔。因此字符串的输入应当允许出现
空格,因此字符串读入不能使用 cin(C++)或者 scanf,必须使用 getch、getchar(C++)
或者 cin.getline()。字符串的存储使用向量 vector,长度自适应,既避免空间的浪费,又不必
限制表达式的长度。
变量和命令的提取采用字符串匹配的方式,区分大小写。变量的存储使用结构体,存
储变量的变量名(小于等于 256 个字符)和变量的数值(默认只能是数字)。
允许使用随意嵌套和并列的括号以及函数,需要对括号进行匹配,基本思想是采用堆
栈处理的方式,当遇到左括号时将下标入栈,遇到右括号时将左括号下标出栈栈并与右括
号的下标匹配。
无括号四则表达式的运算主要运用运算符分割的原理,将表达式分割为数字和表达式
部分分别解析并计算。要求能够处理负数,因此会出现+-、--、*-、/-等运算符相连的情况,
基本的处理思想是区分开双目运算符减号和单目运算符负号,当出现+-、--、*-、/-等情况
时,将第二个负号替换为#,数字解析时,再将#解析为负号。如图 3。
数字解析首先根据前缀或者后缀识别数字进制,然后根据小数点识别是整型还是浮点
型,再将每一位乘以相应的权值并求和,从而将数字转化为十进制。
3
数字解析模块
命令解析模块
变量解析模块 函数解析模块
按优先级计算模块
字符串输入模块
自定义运算符
解析模块
字符串分割模
块
图 1 系统架构