四则运算
摘要:
1、第一阶段目标:重构四则运算-- 能把计算的功能封装起来,通过API 接口调用计算方法。定义一个计算核心类:把四则运算的计算功能包装在一个模块中 (这个模块可以是一个类 Class, 一个DLL等等)。“计算核心”模块和调用类它的其他模块之间是什么关系呢? 它们要通过一定的API (Application Programming Interface) 来和其他模块交流。这个API 接口应该怎么设计呢? 可以从下面的最简单的接口开始:Calc()
这个Calc 函数接受字符串的输入(字符串里就是运算式子,例如 “ 5+3.5“, “7/8 – 3/8 ”, “3 + 90 * (-0.3)“ 等等),这个模块的返回值是一个字符串,例如,前面几个例子的结果就是 ( ”17.5“, “ 1/2”, “-24“).
2 第二阶段目标 - 通过测试程序和API 接口测试其简单的加减乘除功能。并能看到代码覆盖率。可以扩展 Calc() 的定义,让它接受一个新的参数 “precision”, 或者可以启用一个新的函数 Setting()。最多4 个运算符数值范围是 -1000 到 1000精度是小数点后两位怎么通过API 告诉我们的模块呢? 我们当然可以用函数的参数直接传递,但是参数的组合很多,怎么定义好参数的规范呢? 建议大家考虑用 XML 来传递这些参数。增加了新的Setting() 函数之后,要让模块支持这样的参数,同时,还要保证原来的各个测试用例继续正确地工作。
3第三阶段目标 – 定义异常处理。如果输入是有错误的,例如 “1 ++ 2”, 在数值范围是 -1000 .. 1000 的时候,传进去 “10000 + 32768 * 3”, 或者是 “ 248.04 / 0” 怎么办? 怎么告诉函数的调用者 “你错了”? 把返回的字符串定义为 “-1” 来表示? 那么如果真的计算结果是 “-1” 又怎么处理呢?建议这个时候,要定义各种异常 (Exception), 让 Core 在碰到各种异常情况的时候,能告诉调用者 - 你错了! 当然,这个时候,同样要进行下面的增量修改:定义要增加什么功能 - 例如:支持 “运算式子格式错误” 异常,写好测试用例,传进去一个错误的式子,期望能捕获这个 异常。 如果没有,那测试就报错。在 Core 模块中实现这个功能,测试这个功能, 同时测试所有以前的功能,保证以前的功能还能继续工作 (没有 regression), 确认功能完成,继续下一个功能。
代码:
package yunsuan; import java.util.*; public class Cal { public char[] op = {'+','-','*','/','(',')'}; public String[] strOp = {"+","-","*","/","(",")"}; public boolean isOp(char c){ for(int i=0;i<op.length;i++){ if(op[i]==c){ return true; } } return false; } public boolean isOp(String s){ for(int i=0;i<strOp.length;i++){ if(strOp[i].equals(s)){ return true; } } return false; } /* * 处理输入的字符串 * 将他分成一个一个的字符串 */ public List<String> work(String str) { List<String> list = new ArrayList<String>(); char c; StringBuilder sb = new StringBuilder(); for(int i=0;i<str.length();i++){ c = str.charAt(i); if(!isOp(c)){ sb.append(c); } else{ if(sb.toString().length()>0){ list.add(sb.toString()); sb.delete(0, sb.toString().length()); } list.add(c+""); } } if(sb.toString().length()>0){ list.add(sb.toString()); sb.delete(0, sb.toString().length()); } return list; } /* * 输出检测 */ public void printList(List<String> list){ for(String o:list){ System.out.print(o+" "); } } /* * * 中缀表达式转换成后缀表达式 */ public List<String> translate(List<String> str) { List<String> list=new ArrayList<String>(); Stack<String> stack = new Stack<String>();//暂存操作符 for(int i=0;i<str.size();i++) { String s=str.get(i); if(s.equals("(")){ stack.push(s); }else if(s.equals("*")||s.equals("/")){ stack.push(s); }else if(s.equals("+")||s.equals("-")) { if(s.equals("-")&&stack.peek().equals("(")) { i++; list.add("-"+str.get(i)); continue; } if(!stack.empty()) { while(!(stack.peek().equals("("))) { list.add(stack.pop()); if(stack.empty()) { break; } } stack.push(s); } else { stack.push(s); } } else if(s.equals(")")) { while(!(stack.peek().equals("("))) { list.add(stack.pop()); } stack.pop(); } else { list.add(s); } if(i==str.size()-1) { while(!stack.empty()) { list.add(stack.pop()); } } } return list; } /* * 后缀表达式的计算 */ public Double docal(List<String> list) { Stack<Double> stack=new Stack<Double>(); for(int i=0;i<list.size();i++) { String s = list.get(i); Double t=0.0; if(!isOp(s)) { t =Double.parseDouble(s); stack.push(t); } else { if(s.equals("+")) { Double a1 = stack.pop(); Double a2 = stack.pop(); Double v = a2+a1; stack.push(v); } else if(s.equals("-")) { Double a1 = stack.pop(); Double a2 = stack.pop(); Double v = a2-a1; stack.push(v); } else if(s.equals("*")) { Double a1 = stack.pop(); Double a2 = stack.pop(); Double v = a2*a1; stack.push(v); } else if(s.equals("/")) { Double a1 = stack.pop(); Double a2 = stack.pop(); Double v = a2/a1; stack.push(v); } } } return stack.pop(); } }
package yunsuan; import java.util.Scanner; import java.util.*; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in=new Scanner(System.in); Cal cal=new Cal(); System.out.println("请输入一个计算式:"); String str=in.next(); List<String> list=cal.work(str); List<String> list2=cal.translate(list); /*cal.printList(list); System.out.println(); cal.printList(list2); System.out.println();*/ System.out.println(cal.docal(list2)); } }
结果: