采用C++开发的自由函数计算器课程设计Word文档格式.docx
- 文档编号:18502184
- 上传时间:2022-12-18
- 格式:DOCX
- 页数:12
- 大小:129.53KB
采用C++开发的自由函数计算器课程设计Word文档格式.docx
《采用C++开发的自由函数计算器课程设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《采用C++开发的自由函数计算器课程设计Word文档格式.docx(12页珍藏版)》请在冰豆网上搜索。
2.字符识别方案:
写一套数字转换、运算符转换的函数,将字符串转换为数字和运算符标记量。
对数学函数名,编写字典对其进行处理,遍历字典来识别输入的数学函数,并连接到对应的处理程序。
3.优先级分配解决方案:
①内层的括号高于外层的括号。
②数学函数高于乘除,乘除高于加减。
4.提高扩展性解决方案:
首先,运用函数指针作为数据与处理函数的中间传递者;
其次,编写数学函数字典作为函数指针寻找处理函数的仓库。
这样,函数指针可以单纯的只面向输入数据和一个字典。
而字典里有若干条记录,涵盖所有可处理的函数,格式统一,可由函数指针随意调用。
2关键技术
2.1关键技术
本项目主要包括三项关键技术:
数学语言的识别、数学优先级的分配和扩展性。
这三项技术由程序里的相应三个模块来实现。
2.1.1数学语言的识别
主要是对+-×
÷
()和sincos等数学符号的识别,并准确定位其参数的位置,转换成数学形式,计算出结果。
本项目编写了一个“符号字典”来存储各种可以使用的数学符号,在识别数据时将用户输入的符号与“符号字典”里的符合进行一一比较,找到匹配的时候就识别出来。
structMathMathFun[]=
{
{"
+"
Plus_Math},
-"
Minu_Math},
*"
Mult_Math},
/"
Divi_Math},
"
Dh_Math},
("
Lpar_Math},
)"
Rpar_Math},
sin"
Sin_Math},
cos"
Cos_Math},
tan"
Tan_Math},
sqrt"
Sqrt_Math},
abs"
Abs_Math},
pow"
Pow_Math},
mod"
Mod_Math},
log"
Log_Math}};
本项目所建“符号字典”为:
这是一个结构体,结构体的第一项是一个字符串,内容是数学运算符,第二项是一个函数指针,保存了处理这种数学运算的函数的地址。
这个字典可以随时在末尾追加新的数学函数条目,而无需关心是否连接到函数指针,因为函数指针会遍历这个字典,从而找到相应的处理函数,无论是新加的还是以前已有的。
中间空的两个是给次方符号“^”和取余符号“%”预留的。
如果升级双目运算符,可以在“(”前添加,就像在末尾追加新的数学函数条目一样。
用户输入数学函数的格式必须是“函数名称(参数列表)”的形式,括号不能省略,而括号内的参数个数不限,这项技术稍后介绍。
代码清单2.1“符号字典”
在增加字典新条目的时候要注意,第一项的字符串必须是小写,因为本项目在处理用户输入的时候会把所有大写转换为小写,然后再与“符号字典”里的内容比对。
字典第二项是程序里处理某种特定数学符号的子函数的首地址,也就是函数名。
例如我们有一个处理sin()这个数学函数的子函数程序Sin_Math(),那么这里就写Sin_Math,不带参数列表和括号。
“符号字典”中的每一个条目用一对“{}”包起来,各个条目之间用“,”间隔。
“符号字典”的每一条内容都分成两段,前一段是与用户输入的数学函数名称相同的字符串,后一段是处理这个数学函数的程序入口地址(程序的函数名),这就需要一个新的数据类型来保存着一条内容。
于是本项目里构建了一个结构体来存储它。
下面代码清单2.2是“符号字典”结构体的定义:
structMath
charFunName[OAFLENGTH];
//存储数学函数名的字符串
double(*pFun)(data_p);
//存储数学函数名的函数指针
}
代码清单2.2“符号字典”结构体的定义
在这个结构体当中,FunName[]是一个字符串,它的长度LENGTH是一个宏定义。
(*pFun)(data_p)是函数指针,其参数列表是输入字符的结构体类型指针。
这样一个结构体,就能定义出“符号字典”每一条内容的数据类型。
图2.1用流程图说明了用户输入“sin
(2)”是怎样被识别的:
图2.1程序运算“sin
(2)”的流程
经过上述运算,sin
(2)能被正确得计算出为“0.909297”,并可以将结果保存入文件。
2.1.2数学优先级的分配
本项目所开发的“自由函数计算器”是一种表达式计算器,对它的基本要求就是能够在用户任意输入数学算式的情况下,软件都有识别出来,并按照数学规则进行运算,最后输出结果。
这里最关键的一点,就是如何让软件能够“按照数学规则”来工作。
这里最重要的一条“数学规则”就是对不同的运算划分优先级。
显然,三角函数的优先级高于乘除,乘除的优先级高于加减,而且括号又可以改变上述优先级。
如果没有括号的话,只需让程序按照三角函数→乘除→加减的时序来运算,就自然区分出优先级来了,因为越早进行的运算,优先级越高。
然而加了括号后,优先级被改变,按照上述方法来进行,就行不通了。
针对括号的极大灵活性,本程序采取了“时序优先级”的处理方法。
所谓“时序优先级”,就是无论括号嵌套多少层,都首先从最里面的一层括号开始计算,最里面的括号内必然只有数学函数、乘除、加减这三种运算,就可以按照无括号的情况处理。
在最里面的括号运算完成之后,将这个括号用它的结果来代替,这样,就消除了一层括号。
然后递归处理运算式。
对于并排的括号,按照从左到右的顺序对括号进行计算。
这样,无论有多少括号,都能一一消除,并且结果正确。
如图2.2图所示下:
图2.2多层嵌套括号的处理
2.1.3扩展性
扩展性主要是运用函数指针,实现对数目众多的数学处理函数的调用。
在针对运算数据时只有一个操作者,那就是函数指针,然后函数指针会把数据带给对应的数学处理函数来处理,实现准确的计算。
本项目使用了一个前面刚刚介绍过的结构体来连接用户输入的数学符号与程序的数学处理函数。
函数指针在程序中扮演的角色如图2.3所示:
图2.3函数指针所扮演的角色
使用函数指针还有一个问题,就是参数列表该如何处理。
如果函数指针声明的时候只有一个参数,那么它指向的函数也只能有一个参数,但是本项目要让这个函数指针既能处理sin
(2)这样的单个参数的数学函数,又能处理像log(2,8)这样的两个参数的数学函数,以后还可能加上函数更多参数的函数。
那么,如何让函数指针变成能够指向含有任意个参数的函数呢?
只有这样才能真正实现一劳永逸,大大提高扩展性。
本项目所设计的方法是将函数指针的参数列表写为一个参数的地址,这样,如果有n个参数,那么就传递第一个参数的地址给它,后面的几个参数由具体的运算函数安装地址去取。
例如:
log(2,8),那么本程序在识别到log后,让函数指针指向程序里预先编写好的处理函数Log_Math(),并将第一个参数“2”的地址也传递过去,于是Log_Math()按照传递过来的地址,先找到第一个参数的值“2”,在将地址往后寻找,接着就找到了“8”,于是,Log_Math()获得了足够的参数,就可以开始运行计算了。
这样,无论函数包含多少个参数,都能用这个函数指针来操作,扩展性大大提高,以后如果要增加新的数学函数处理功能,只需添加相应的处理函数即可,而无需改动数据识别与数据获取部分。
3详细设计:
关键代码
本项目的关键代码有三大部分,一是识别用户输入部分,二是扩展性部分,三是分优先级运算部分。
3.1用户输入识别关键代码
存储用户输入内容的链表的节点结构体定义为:
typedefstructdatanode
charorigin;
//初始输入的字符
doubleresult;
//转化后的数字
intoperators;
//初始为9999,表示无效
structdatanode*from,*next;
}datas,*data_p;
代码清单4.1结构体定义
本程序以上面的结构体为节点,构造一个链表来存储用户输入的内容。
在对数据由char型转换为double型时,就是将节点中的origin转化到result中去,转换与识别代码详见附录一。
3.2扩展性关键代码(即“符号字典”)
这里定义了本程序可处理的运算符和数学函数的名字(字符串形式),这就是可处理的数学运算的汇总表,升级时,只需修改(增加)用注释“//↑↑↑”标记的部分即可,总共有两个这样的部分。
#defineLENGTH12//每个运算符的最大长度
//定义存储数学函数名称和运算函数首地址的结构体
charFunName[LENGTH];
//存储数学函数名的函数指针
};
//定义运算函数实体
doubleSin_Math(data_pp)
Check_NumOfParameter("
p,1);
return(sin(p->
result));
doubleCos_Math(data_pp)
return(cos(p->
//其它函数实体代码略
//↑↑↑升级时这里增加一个处理函数体
//定义OAFSIZE个结构体,并赋值;
形成一个数学函数符号字典
Sin_Math},
Cos_Math},
Tan_Math},
Pow_Math},
Log_Math}//↑↑↑升级时这里增加一个函数名称字符串和函数首地址(函数名)
constintOAFNUM=sizeof(MathFun)/sizeof(MathFun[1]);
//数学函数字典的数目
代码清单4.2函数字典及处理函数实体
4设计结果和使用说明
4.1界面总介绍
本程序开始使用C-Free开发,算法实现后,用C++Builder6开发用户使用界面,最终界面如图5.1所示:
图5.1软件最终界面
上面有一个文本框,可以输入和现实文本。
文本框下面有两个选择项,选择“文件输入”时,文本框锁定只读,只能显示打开文件的内容,不可编辑。
但可以双击文本框解锁来编辑文本;
选择“键盘输入”时可以再文本框里输入内容。
下面有三个按钮,分别是“装载文件”、“计算”、“保存结果”。
当单击“装载文件”时弹出打开文件对话框,可以选择一个文本文件打开,它将显示在文本框里。
单击“计算”按钮,文本框里的算式(无论是文件输入还是键盘输入的)会被运算,并连同结果一起显示在文本框里。
一次可以计算多个算式,当然,这些算式也可以手动输入,它们以“=”或回车表示一个算式的结束。
4.1.1目前本计算器支持的运算种类
1.加减乘除。
2.括号。
3.三角函数sincostan。
4.取模运算(绝对值)abs(x)
5.对数运算log(x,y),x为底数。
其它运算随时可以添加,利用本程序优异的扩展性,升级功能非常简单。
4.1.2计算结果
单击“计算”按钮,程序进行计算,如果含有非法字符,程序会通过报错来指出你那里输入错误。
4.1.3输入报错的项目
1.无法识别的符号,如:
引号、大括号、冒号,已经不是可处理的数学函数的英文字母组合等。
2.连续的加减乘除等运算符。
3.除数为0的情况。
4.括号不匹配的情况。
5.数学函数参数个数不正确;
参数取值范围不正确。
4.1.4软件的自动容错功能
1.自动忽略空格输入。
2.自动将前面没有算式的换行符忽略。
3.自动将输入的大写字母转换为小写字母。
5测试
对本程序进行了比较全面的测试,以下是测试用例及测试效果:
表格6.1测试清单
编号
测试内容
输出结果
1
9-8+sin(5)
【正确】0.041076
2
1&
3
【报错】“你输入了非法字符,请更正输入”
syr(999)
4
1*+2
【报错】“你输入了连续的运算符,请更正输入”
5
1+(*2)
6
1/0
【报错】“你输入的除数为0,请更正输入”
7
1/(9-9)
8
6+(7+(8-9)
【报错】“你输入的“(”与“)”个数不匹配!
”
9
sin(1,2)
【报错】“你输入的sin参数过多,请更正输入”
10
log(9)
【报错】“你输入的log参数过少,请更正输入”
11
log(2,0)
【报错】“log的参数不能为0,请更正输入”
12
log(1,2)
【报错】“log的底数不能为1,请更正输入”
13
1.2.3
【报错】“同一个数字不能有多个小数点!
6参考
[1].谭浩强著,C程序设计(第三版).北京:
清华大学出版社,2005
[2].陈正冲著,C语言深度解剖,网络版
[3].徐孝凯等著,数据结构.北京:
清华大学出版社,2004
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 采用 C+ 开发 自由 函数 计算器 课程设计