科学计算器JAVA.docx
《科学计算器JAVA.docx》由会员分享,可在线阅读,更多相关《科学计算器JAVA.docx(34页珍藏版)》请在冰豆网上搜索。
![科学计算器JAVA.docx](https://file1.bdocx.com/fileroot1/2023-1/10/b22a8f31-5090-4a6d-877e-d1bdeba3b3df/b22a8f31-5090-4a6d-877e-d1bdeba3b3df1.gif)
科学计算器JAVA
一、综合训练目的与要求
1.巩固和加深对课堂所学知识的理解与应用;
2.学习掌握一般的软件的设计方法和查阅、运用资料的能力;
3.掌握JAVA程序设计语言,面向对象的软件设计思想、方法。
二、综合训练任务
1.设计一个简易的计算器;
功能要求:
能实现基本的加、减、乘、除运算,以及表达式计算(加减乘除括号负号);二、八、十、十六进制间的相互转化,带符号的左移右移;逻辑与或非异或的运算;
其他功能:
开方、求倒数、化百分数、求平方、求立方、求x的y次方、求阶乘、取余、取整(取小数点之前的)、求常用对数、求三角函数;界面简洁适用。
2.设计任务要完成设计、编码、测试等过程,给出设计思路、主要的代码及其说明。
3.整个过程要体现面向对象的思想。
三、总体设计
主界面设计图(见附录1)
四、详细设计说明
(一)界面设计:
1.先将窗体分为两大块,添加菜单栏,在菜单栏中添加菜单,在菜单中添加菜单项;均以数组的形式添加;
2.第二块添加文本显示框于窗体北部,令添加一个面板jp于窗体中心,将这个面板布局为边界布局管理器,分为上下两部分,上部分jpup添加到该面板北部,下部分jpdown添加到jp面板中心;
3.将jpup面板布局为一行两列的网格布局管理器,在左边添加面板jp1,在右边添加面板jp2,jp1面板中放四个按钮,分别为四种进制,用来控制进制转换。
jp2面板中放七个按钮,分别为三个控制角度弧度梯度转换的,四字、双字、单字、字节按钮,控制输入的二进制位数;
4.将jpdown面板布局为一行两列的网格布局管理器。
将jp3面板和jp4面板分别添加进去。
jp3和jp4面板均设为边界布局管理器。
5.将jp5面板和jp6面板分别加入jp3面板的北部和中部;jp5面板中放两个复选框和两个文本框(做填充效果,不可编辑);
6.将jp6面板布局为五行五列的网格布局管理器,以数组的方式添加25个按钮jb1[i]=newJButton(s1[i]);
7.将jp7和jp8分别添加到jp4面板的北部和中部,jp7面板里添加四个按钮,第一个是用来做填充效果的按钮,其余三个分别是(Back)退格、(CE)清除、(C)清除。
8.将jp8面板布局为五行六列的网格布局管理器,,以数组的方式添加25个按钮jb2[i]=newJButton(s2[i])。
(二)添加动作监听事件:
1.对菜单添加事件:
当点击三个菜单(编辑、查看、帮助),会显示对应的下拉菜单;当点击编辑菜单中的复制时,条用copy函数;当点击编辑菜单中的粘贴时,调用paste函数;当点击查看菜单中的标准从科学计算器回到简易计算器界面,此实现时通过隐藏jpup面板和jp3面板,然后调整窗体大小,即可实现面板收起的效果。
当点击科学的时候又回到科学计算器界面。
当点击菜单中的进制按钮时,某种进制中没有的数值将被屏蔽掉。
当点击帮助时会看到关于计算器,此时点击会弹出关于记事本的帮助文档。
2.对按钮添加事件:
设置一个全局变量append,判断是追加(true)还是替换(false);
对于数字键,采用字符串中的indexOf函数,如果点击的按钮值能在“0123456789”中找到,则有对应位置返回值,如果找不到,则返回值为-1;
当点击小数点时,判断文本框中的最后一位是不是小数点,如果是,截取掉,如果不是添加一个小数点;
当点击正负号时,判断文本框中的最后一位是不是负号,如果是,截取掉,如果不是添加一个负号;
当点击加减乘除运算符号时,可追加;当点击等号时显示表达式结果,并且将全局变量置为false,此时输入只能替换。
3.对左半边按钮添加事件:
当点击正弦、余弦、正切按钮时,调用Math类里面的正弦、余弦、正切函数;当点击求平方、立方按钮(点击后append置为false)时,将文本框里的字符串转换为double型,进行平方、立方,重设为文本框内容;当点击求倒数按钮时,先判断其是不是0,是0不能求倒数,如果是1,倒数直接置为1,如果不是0或1,则转为double值,用1除以该值。
当点击求阶乘的按钮时,获取文本,调用Convert类中的求阶乘的函数;当点击pi或e是文本框里显示圆周率或自然指数e的值;当点击log或ln时,调用Math里面的对应函数;当点击左移或右移时,append被置为false,等待输入左移或右移的位数,当点击了等号后,调用Convert类里的左移或右移函数;设置一个全局变量prestatu,默认值为1,代表10进制,0代表十六进制,2代表八进制,3代表二进制,当点击某种进制按钮时,如果文本框不空,会将文本框里的字符串做相应处理,在根据prestatu的值确定从哪个状态装换为此进制,调用Convert类里对应的进制装换函数,做完后将prestatu的状态值改为当前状态值,作为下一次判断从哪种进制向哪种进制转换的依据;当点击求x的y次方按钮时,此时输入替换第一操作数,点击等号后,调用Math类里的pow函数;
4.对右半边按钮添加事件:
当点击数字按钮或加减乘除及括号正负号按钮,本系统将判断其是否合法,若合法,在点击等号后调用Compute类的计算函数,计算完成后,将值传回,替换表达式;当点击Mod(取余)时等待输入的第二参数将替换第一参数,点击等号后,调用BigInteger类里的mod函数,显示余数;当点击Int时将文本框里的小数点后的字符串省略掉,达到取整的效果。
(三)、表达式求值:
将文本框中的合法的表达式(此时是字符串)传入Calculate函数;
当表达式字符串传进来之后,先正确拆分表达式(如3.5要作为一个操作数一起拆出来)存储于input数组中。
这个拆分主要是利用String类里的substring函数,以运算符为边界,当发现运算符时,截取该位与上一个运算符之间的数作为一个操作数,同时截取该操作符。
正确截取结束后,遍历input数组,若是数字,直接进入post数组。
若是左括号直接入栈。
若是右括号,采用while循环判断栈顶是不是左括号,如果不是,将栈顶元素出栈放入post数组中,如过栈顶是左括号,则直接出栈。
如果是加减乘除,先判断栈是否空,如果栈空则直接入栈,采用while循环判断,如果栈不空且栈顶元素优先级高于当前input[i]的优先级且栈顶不是左括号时,将栈顶元素出栈放入post数组中,当while循环条件不成立时,直接入栈。
(四)进制转换:
通过一组单选按钮控制进制间的转换,转换思路:
二进制、八进制、十六进制向十进制转换时调用我写的函数XTOD(Strings,intn),s为要转化的数,n代表从n进制转换为十进制。
采用for循环遍历s字符串,每次从后截取字符串的每一位,判断是不是十六进制中的特殊字母,如果是换为对应的数值与Math.pow(n,i)相乘,如果不是则使用Integer.parseInt(s)将截取的元素换为int型与Math.pow(n,i)相乘;在函数开始设置一个变量sum,在for循环内部设置临时变量a存储每次的结果,循环一次执行一次sum=sum+a;最后for循环结束后,将sum转换为字符串传回。
当十进制想其他进制转换时,调用相应的函数。
转换思路:
先判断这个数与要转化的基数,如果小于基数,直接保存起来,如果不是,设置一个变量记录除的次数s,用while循环判断概述如果大于等于基数,则用它除以基数,s++,循环结束之后创建数组长度为s的数组,用来存放余数。
最后倒序遍历数组,链接成字符串返回。
(五)左右移位:
左移位:
<<,有符号的移位操作
左移操作时将运算数的二进制码整体左移指定位数,左移之后的空位用0补充
右移位:
>>,有符号的移位操作
右移操作是将运算数的二进制码整体右移指定位数,右移之后的空位用符号位补充,如果是正数用0补充,负数用1补充。
对于左移:
先以要移位的字符串长度创建一个String型数组,我令数组长度为length,然后根据移位的位数n,采用for循环将原字符串的前length-n位循环拷贝到新建的数组的前length-n位,在剩余的数组位置添加0。
最后遍历数组,连接字符串返回。
对于右移:
先以要移位的字符串长度创建一个String型数组,我令数组长度为length,先判断第一位是1还是0,如果是1,采用for循环,当i是小于要右移的位数时,则在新建的数组中填1;当i大于等于要右移的位数时,则截取原字符串的前n位填入新建数组的后length-n位中。
如果第一位是0,则在前n为填0,其他一样。
(六)逻辑与或非异或:
比较两个字符串的每一位,或运算:
若有一个是1,则或运算为1,否则为0;与运算:
若有一个为0,则为0,否则为1;异或运算:
若两个字符串对应位不同,则为1,否则为0;取反运算,将0换为1,将1换为0;以上这些均在for循环中进行,每次循环都会更新结果字符串,最后将结果字符串返回。
当然在进行与运算前,考虑两个字符串长度,把左边多出来的部分舍弃,因为多出来的部分相当于与0对齐。
(其实,严格来说,应该按照机器中二进制表示的位数来确定的);对于或运算和异或运算前,也要考虑字符串长度。
将多出来的部分进行循环遍历,如果是0则在结果字符串中加上0;如果是1则在结果字符串中加1;因为1或0运算是1,1异或0运算时1,0或0,0异或0都是0.
五、调试与测试
1.标准计算器界面:
点击查看菜单中的标准即可跳转到此界面。
2.科学计算器界面:
点击查看菜单中的科学即可跳转到此界面。
3.表达式求值测试:
用户用鼠标点击按钮或键盘输入表达式,点击等号后,会验证表达式是否合法,如果不合法会提醒用户检查修改;如果合法则计算后用结果替代表达式。
结果显示:
表达式测试2:
表达式中有负号时,用正负号或减号都可以。
结果显示:
表达式求值测试2:
表达式中有小数的
结果显示:
表达式测试3:
结果显示:
表达式验证:
进制转化测试:
十进制转化为八进制
八进制转换为二进制:
二进制转换十六进制:
四种进制之间的相互转换均已实现。
本系统的缺陷是:
对于小数不能实现进制转换。
没有实现科学计算器的统计功能。
左右移位、与或非异或运算也实现了,但是没有考虑机器中二进制的表示位数。
六、实习日志
2011年12月31日:
分析题目,确定要实现的功能:
表达式求值,进制间的相互转换,带符号的左移和右移,及其一些辅助功能,选择使用语言,完成实习任务书。
2012年1月3日:
敲代码,实现科学计算器主界面,并且添加部分事件,实现控制一些按钮不可用,实现按钮的不同颜色。
凡事只要耐心点,再难的事,也会变得简单。
通过查看JDK资料,及自己多多思考练习,终于完成了今日功能。
2012年1月4日:
添加进制按钮事件,控制不同进制的非法数字不可用,添加清除按钮事件;添加正弦、余弦、正切、求倒数、求阶乘、求百分数、取整、取余、求平方、求立方、求对数、求指数等事件。
今天的实习中发现有很多细节性问题,所以要养成良好的习惯。
细节决定成败,态度决定一切。
只要我耐心,就会成功。
2012年1月5日:
添加表达式按钮事件及等号事件,完成表达式运算函数。
这是此次实习最重要的部分,所以花费了很多时间,也遇到了各种各样的问题,不过经过我的仔细分析,不断调整代码,最终将表达式求值实现。
遇到问题,绝不退缩,迎难而上。
2012年1月6日:
今天发现表达式中以括号开始的表达式有问题,经过研究,发现是在拆分表达式时,当i=0时,截取了两次括号,导致错误,因此对于判断条件添加一个i!
=0时才执行。
2012年1月8日:
对于以负数开始的表达式计算有问题,经过研究,当遍历到的是负号时,添加一个判断语句,如果i=0,且input[i+1]匹配到double型数或者int型数字时,先向post数组放入一个0,然后继续向下走。
对于表达式中间出现的负数,则先判断负号前面是左括号,后面是double型数或者int型数即可先在post数组里放一个0,再继续往下走。
212年1月9日:
实现从十进制向二进制、八进制、十六进制转换的函数和从二、八、十六进制到十进制转换及其之间的相互转换。
这一块基本算法懂,所以写时只要注重细节就可以了。
最后开始写课程论文。
2012年1月10日:
测试调试代码,实现带符号的左移右移(没有考虑机器中二进制的表示位数)。
完善课程论文。
最近发现自己挺迷恋程序的,当遇到问题没有解决时,每天走路上想,吃饭时想,睡觉也想,连娱乐都放弃了。
不要轻言放弃,一定会有收获。
2012年1月11日:
制作答辩ppt,继续完善课程论文,测试规范代码。
思考能否完善或添加新的功能。
2012年1月12日:
答辩了,实习结束了,这次的实习代码完全是自己一字一句的敲出来的,所以还是蛮开心的,而且感觉收获很大,最重要的是我发现自己挺喜欢研究程序的,尤其是遇到问题时,总能自己动手画图,调试,添加注释语句琢磨着解决问题,所以特别开心。
七、实习总结
通过为期两周的紧张实习,我对于面向对象的程序设计有了更深刻得了解,对面向对象的思想体会更深刻。
面向对象的特点是抽象、封装、继承、多态性。
系统中一切皆为对象;对象是属性及其操作的封装体;对象可按其性质划分为类,对象成为类的实例;实例关系和继承关系是对象之间的静态关系;消息传递是对象之间动态联系的唯一形式,也是计算的唯一形式;方法是消息的序列。
通过这次实习,我对于编写一个小型软件有了一定的认识,首先我们要做好需求分析,分析我们要做什么软件,给哪些人用,从他们的角度考虑,有什么特殊需要。
分析清楚需求,着手设计,看有哪些功能,分几块做;将每一块封装成一个类,然后设计类,分析用到的属性,方法,考虑他们的修饰符,访问权限等。
然后还要考虑用到哪些算法,尽量都将他们封装起来,这样可以方便代码重用。
有了一个详细的规划后,开始着手一步一步敲代码,当然要视情况而改变一些策略。
这次实习思路明确,在做好需求之后,有了一个规划,确定了要实现的功能,开始完成每一块的代码,并进行测试,最后对整体代码进行测试调整。
实习过程中遇到很多问题,因为我做的是计算器,并且用的是java语言,然后老师都说他们java忘了,那我只能自己动手解决了。
所以,刚开始很笨,就不停地画表达式计算的过程图,然后发现了问题,并解决了问题,结果一个本子画完了,发现自己好笨。
到下次遇到问题,我就添加一些打印语句,然后很快发现了问题的所在处,也顺利的解决了问题,这样就高效多了。
所以说通过这次实习我真正的学会了调代码,而且我也不再怕遇到错了,因为当我自己将错误解决的时候很高兴,同时我还帮助其他同学解决了很多问题,当然也从一些同学那里学到好多东西。
这次实习的缺憾就是,我没有学习QT、MFC的知识,通过和其他同学的交流,以及看他们所作的东西,我挺感兴趣的,所以我下载好了资料,电脑上也装好了数据库,回家后自己继续学习,多做几个题目,好好练一练。
我觉得这个实习特别有意思,大家一起做,不会了交流一下,能学到好多东西。
珍惜这种学习机会,下学期就剩下一次了。
通过这次实习,我发现其实再简单的东西要动手做也挺难得,但是只要认真做认真分析其实也挺简单的。
世上无难事,只怕有心人。
都说信管的编程能力弱,其实都是我们在逃避,我们要有探索和征服的精神,只有这样你才会有继续前进的动力。
充实的实习生活结束了,回家好好充充电,下学期更加美好。
八、附录:
核心代码清单
1.表达式求值代码:
importjava.util.Stack;
publicclassJisuan{
privateStringexpression;//表达式
finalstaticintN=100;//存放表达式的数组最大长度
publicStringgetExpression(){
returnexpression;
}
publicvoidsetExpression(Stringexpression){
this.expression=expression;
}
publicJisuan(Stringexpression){
this.setExpression(expression);
}
//优先级比较
privateintcom(Stringx){
if(x.equals("*")||x.equals("/")){
return2;
}
if(x.equals("+")||x.equals("-")){
return1;
}else{
return-1;
}
}
//算术表达式求值
publicdoubleCalculate(){
Stringexample=newString("()+*/-");
String[]input=newString[N];//存放合法的正确拆分的表达式
String[]Post=newString[N];//存放取除括号的表达式
//Stringexpression="(3.5+6)*(45/38-12)";
intn=expression.length();
intcount=0;
intpre=-1;
for(inti=0;iif(example.indexOf(expression.charAt(i))!
=-1){
if(pre!
=-1&&i!
=pre){
input[count++]=expression.substring(pre,i);
//System.out.println(input[count]);
}
if(pre==-1&&i!
=0){
input[count++]=expression.substring(0,i);
//System.out.println(input[count]);
}
input[count++]=expression.substring(i,i+1);
//System.out.println(input[count]);
pre=i+1;
/*
*pre-11457891215
*i014678111417
*/
}
}
for(inti=0;iSystem.out.print(input[i]);
}
if(preif(pre==-1){
input[count++]=expression.substring(0,n);
}else{
input[count++]=expression.substring(pre,n);
}
}
//for(inti=0;i//System.out.println(input[i]+"");
//}
StackS=newStack();
intj=0;
for(inti=0;iif(example.indexOf(input[i])==-1){
Post[j++]=input[i];
System.out.println("**********1");
}else{
if(input[i].equals("(")){
S.push(input[i]);
System.out.println("**********2");
}elseif(input[i].equals(")")){
while(!
S.peek().equals("(")){
Post[j++]=S.pop();
System.out.println("**********3");
}
S.pop();
System.out.println("**********4");
}else{
if(i==0&&input[i].equals("-")&&input[i+1].matches("^(\\d*\\.\\d*)|\\d$")){
Post[j++]="0";
System.out.println("**********5");
}
if(i==0&&input[i].equals("-")&&input[i+1]=="("){
Post[j++]="0";
System.out.println("**********?
");
}
//if(i==5){
//System.out.println("*"+input[i-1].equals("("));
//System.out.println("*"+input[i].equals("-"));
//System.out.println("*"+input[i+1].matches("^(\\d*\\.\\d*)|\\d$"));
//}
if(i>=1&&input[i-1].equals("(")&&input[i].equals("-")&&input[i+1].matches("^(\\d*\\.\\d*)|\\d$")){
Post[j++]="0";
System.out.println("**********6");
}
if(S.empty()){
S.push(input[i]);
System.out.println("**********7");
}else{
while(!
S.empty()&&com(S.peek())>=com(input[i])&&(!
S.peek().equals("("))){
Post[j++]=S.pop();
System.out.println("**********8");
}
S.push(input[i]);
System.out.println("**********9");
}
}
}
}
while(!
S.empty()){
Post[j++]=S.pop();
}
for(inti=0;iSystem.out.print(Post[i]+"");
}
S.clear();
intm=j;
for(inti=0;iif(Post[i].equals("+")){
doubled=Double.parseDouble(S.pop());
S.push(String.valueOf(Double.parseDouble(S.pop())+d));
}elseif(Post[i].equals("-")){
doubled=Double.parseDouble(S.pop());
S.push(String.valueOf(Double.parseDouble(S.pop())-d));
}elseif(Post[i].equals("*")