之前对附件中的计算器感觉十分不方便,在使用过程中,无法随意更改输入表达式,有时候可能会因为一点输入错误,而面临重新输入的繁琐。尤其是在比较长的表达式的输入中,这种不变体现地更加明显。另外,针对附件中的计算器中的进制转换问题,也很不方便,比如计算中如果既有10进制,又有16进制,就需要不断地点击进制框,这无疑降低了用户体验。
在之后很长一段时间,碰到计算问题,我都是用matlab,但是,matlab在进制输入同样存在不便,必须调用转换函数才能实现,与此同时,matlab缓慢的启动时间和较大的内存消耗,无法令人忍受。之后,我就在考虑自己做一个桌面应用工具,取代这些问题。
借着最近一段时间学习Java的契机,我开始动手实践一直以来的想法。
本项目的难点主要在于:1.要想保存记录,并且方便修改,必须使用文本字符串输入,而文本输入在转换为数字和运算符,存在不便。
2.运算符优先级和括号的存在,为处理增加了难度。
3.个人原因,对一些类库和错误还不是很熟悉,走了一点弯路。
解决办法:
问题1:对字符串中的元素进行判断,进行人为分类,因为数与数之间必然存在运算符进行分割,所以在检测到运算符之后对数进行入队操作。
问题2:运算优先级和括号的存在,只要对队列元素相应附上一个优先级,然后处理过程中对高优先级的先进行运算。因为对数和运算符都用同样的队列来存储,一开始觉得是要给队列中数赋予优先级,然后优先级靠前的2个数先操作,但是这里的问题在于比如检测到*时,既要在队列前一个元素和后一个元素都改写优先级,如果是8*9*7,中间的9的优先级就要比8和7都要大,如果要处理这个问题,就还要识别相邻的运算符,造成设计复杂度的增加。后来想到一个比较好的解决方法是 优先级只是针对运算符,而数只是作为操作对象,这点在逻辑上也很好理解,运算符相当于方法,优先的对象是方法而不是操作对象。这个问题就迎刃而解,但是另一个问题是()的优先级和*/优先级存在定量问题,如果2者在原优先级上的累加量一样,就会造成3*(8-9)中*和-的优先级一样,由于我的从前到后的处理规则就导致了最后3*8-9的运算。
问题3:体会到直接从API或者是直接看官网的技术文档或者官方例程而非从别人的经验中获取的好处。如SWT的类库中layout布局,之前看别人的代码,然后乱,但是最后还不是很能理解,也不可避免地走了一点的弯路。但是从官网的Understanding Layouts in SWT就很快地理解了界面设计的基本方法和步骤。在实践中,也对Java的一些特性有了一定的了解。之前一直看Thinking in Java,但是没有动手实践,理论知识学过就忘,学C语言、HDL的经验告诉我实践才能促进认识,这次实践又加深了我对这点的看法。
下面是核心代码:
package calculation; import java.lang.String; import calculation.CalList; public class MyStrtonum{ static String str; static long num =0; static numtypeenum mynumtype = numtypeenum.decimal; static byte pri = 0;//priority static CalList callist = new CalList(); private enum caltypeenum {numtype,highopertype,lowopertype,leftbrackettype,rightbrackettype,others}; private enum numtypeenum {hex,decimal,binary}; MyStrtonum(String getstr){ str = getstr.toLowerCase(); System.out.println(str); callist.deleteAll(); int ii; for(ii=0;ii<str.length();ii++){ distinguish(str.charAt(ii)); System.out.println(str.charAt(ii)); } callist.insert(num,(byte)(-1)); num = 0; } //@SuppressWarnings("unused") private static caltypeenum isCalChar(int ch){ if(ch>='0' && ch<='9') return caltypeenum.numtype; else if(ch=='+' || ch =='-') return caltypeenum.lowopertype; else if( ch =='*' ||ch =='/' ) return caltypeenum.highopertype; else if((ch>='a' && ch<='f') || ch=='x') return caltypeenum.numtype; else if(ch == '(') return caltypeenum.leftbrackettype; else if(ch == ')') return caltypeenum.rightbrackettype; else return caltypeenum.others; } private static void distinguish(int ch){ switch(isCalChar(ch)) { case leftbrackettype: pri = (byte) (pri + 2);break; case rightbrackettype: pri = (byte) (pri - 2);break; case highopertype: callist.insert(num,(byte)(-1)); System.out.println(num); num = 0; mynumtype = numtypeenum.decimal; callist.insert(ch, (byte)(pri+1));break; case lowopertype: callist.insert(num,(byte)(-1)); System.out.println(num); num = 0; mynumtype = numtypeenum.decimal; callist.insert(ch, pri);break; case numtype: if(ch == 'x') mynumtype = numtypeenum.hex; else if(ch == 'b' && (mynumtype == numtypeenum.decimal)) mynumtype = numtypeenum.binary; else if(mynumtype == numtypeenum.decimal) { if(ch>'9') System.out.println("error decimal"); else num = num*10 + (ch - '0'); } else if(mynumtype == numtypeenum.hex) { num = (num<<4) + ((ch>'9')?(ch-'a'+10):(ch-'0')); } else if(mynumtype == numtypeenum.binary) { if(ch>'1') System.out.println("error binary"); else num = (num<<1) + (ch-'0'); } break; case others:break; default:break; } } public static long numoperation(){ CalNode tempnode; //while() if(callist.Length != 1){ do{ tempnode = callist.gethigherOper(); switch((int)tempnode.next.data) { case '+': tempnode.data=tempnode.data + tempnode.next.next.data; break; case '-': tempnode.data=tempnode.data - tempnode.next.next.data; break; case '*': tempnode.data=tempnode.data * tempnode.next.next.data; break; case '/': tempnode.data=tempnode.data / tempnode.next.next.data; break; default: System.out.println("error"); break; } } while(callist.ReconstructList(tempnode) != 1); } callist.reset(); System.out.println(callist.ShowNode()); long tempdata = callist.ShowNode(); callist.deleteAll(); return tempdata; } /* private static void main(String [] args) { MyStrtonum test = new MyStrtonum("(23-0xa)*20"); test.numoperation(); //test.distinguish('3'); } */ }