前几天要做一个计算数学表达式的题目,本来计划使用解析表达式的方法来解析各种数学表达式,然后再动态计算表达式的值.后来考虑到这样编程的任务很重,时间有限 后来在网上搜搜,看到使用动态编译并使用反射机制 ,这样计算表达式的编程就容易多了.下面是我这次编程的例子, 请大家看看.
java 代码
- /*
- 02 * Created on 2006-3-8
- 03 * @author icerain 我的Blog: http://blog.matrix.org.cn/page/icess
- 04 */
- 05
- 06 public interface IOperator {
- 07 String SIN = "sin";
- 08 String COS = "cos";
- 09 String TAN = "tan";
- 10 String ASIN = "asin";
- 11 String ACOS = "acos";
- 12 String ATAN = "atan";
- 13 String EXP = "exp";
- 14 String LOG = "log";
- 15 String POW = "pow";
- 16 String SQRT = "sqrt";
- 17 String FABS = "fabs";
- 18 String MINUS = "minus";
- 19
- 20 String J_SIN = "Math.sin";
- 21 String J_COS = "Math.cos";
- 22 String J_TAN = "Math.tan";
- 23 String J_ASIN = "Math.asin";
- 24 String J_ACOS = "Math.acos";
- 25 String J_ATAN = "Math.atan";
- 26 String J_EXP = "Math.exp";
- 27 String J_LOG = "Math.log10";
- 28 String J_POW = "Math.pow";
- 29 String J_SQRT = "Math.sqrt";
- 30 String J_FABS = "Math.abs";
- 31
- 32 }
- 定义一个接口, 用来转换各种数学符号为Java类库中的表达式.
- 下面是用来计算的代码.
- 001 /*
- 002 * Created on 2006-3-7
- 003 * @author icerain 我的Blog: http://blog.matrix.org.cn/page/icess
- 004 */
- 005 //package hust.icess.simpson;
- 006
- 007
- 008 import java.util.logging.Level;
- 009
- 010 import java.io.*;
- 011 import java.lang.reflect.Method;
- 012 import java.util.Scanner;
- 013 import java.util.logging.Logger;
- 014
- 015
- 016 import com.sun.tools.javac.*;
- 017 /**
- 018 * 利用Simpson公式计算积分,在输入被积公式时候请注意使用如下格式.
- 019 * 1.只使用圆括号() , 没有别的括号可以使用.如: 1/(1+sin(x))
- 020 * 2.在输入超越函数的时候,变量和数值用括号扩起来 如:sin(x) 而不要写为 sinx
- 021 * 3.在两个数或者变量相乘时候,不要省略乘号* 如:2*a 不要写为 2a
- 022 * 4.在写幂运算的时候,请使用如下格式:
- 023 * 利用动态编译来计算Simpson积分,使用该方法 编程相对简单,运行效率有点慢.
- 024 * @author icerain
- 025 *
- 026 */
- 027 public class Simpson implements IOperator {
- 028 /**
- 029 * Logger for this class
- 030 */
- 031 private static final Logger logger = Logger.getLogger(Simpson.class
- 032 .getName());
- 033
- 034 private String expression = null;
- 035
- 036 private String variable = null;
- 037
- 038 private String[] variableValue = new String[3];
- 039
- 040 // private static Main javac = new Main();
- 041
- 042 /**主函数 */
- 043 public static void main(String[] args) throws Exception {
- 044 Simpson sim = new Simpson();
- 045 System.out.println("结果如下:");
- 046 System.out.print(sim.getSimpsonValue());
- 047 System.exit(0);
- 048
- 049 }
- 050
- 051 public Simpson() {
- 052 logger.setLevel(Level.WARNING);
- 053 init();
- 054 }
- 055
- 056 /** 初始化用户输入,为技术Simpson积分做准备. */
- 057 private void init() {
- 058 Scanner scanner = new Scanner(System.in);
- 059 System.out.println("请输入函数表达式 如 1+sin(a) + cos(a)/a :");
- 060 // String input = scanner.nextLine();
- 061 //读入被积函数的表达式
- 062 expression = scanner.nextLine().trim().toLowerCase();
- 063 System.out.println("请输入变量字符 如 a :");
- 064 //读入变量字符
- 065 variable = scanner.nextLine().trim().toLowerCase();
- 066
- 067 //处理多元函数 目前不实现该功能
- 068 // String[] tempVars = tempVar.split(" ");
- 069 // for(int i = 0; i < tempVars.length; i ++) {
- 070 // variable[i] = tempVars[i];
- 071 // }
- 072
- 073 System.out.println("请输入积分区间和结点数 如 2 5.4 10 :");
- 074 //读取复合Simpson公式的积分参数
- 075 String tempValue = scanner.nextLine().trim();
- 076 String[] tempValues = tempValue.split(" ");
- 077 for (int i = 0; i < tempValues.length; i++) {
- 078 variableValue[i] = tempValues[i];
- 079 }
- 080
- 081 }
- 082
- 083 /** 计算 Simpson积分的值*/
- 084 public double getSimpsonValue() {
- 085 //保存中间结果
- 086 double value1 = 0;
- 087 double value2 = 0;
- 088 double tempValue = 0;
- 089 int i = 0;
- 090 // 解析输入的积分参数值
- 091 int n = Integer.parseInt(variableValue[2]);
- 092 double a = Double.parseDouble(variableValue[0]);
- 093 double b = Double.parseDouble(variableValue[1]);
- 094 double h = (b - a) / n;
- 095 //计算value1
- 096 for (i = 0; i < n; i++) {
- 097 tempValue = a + (i + 0.5) * h;
- 098 String code = getSourceCode(expression, getVariable(), Double
- 099 .toString(tempValue));
- 100 try {
- 101 value1 += run(compile(code));
- 102 } catch (Exception e) {
- 103 // TODO Auto-generated catch block
- 104 e.printStackTrace();
- 105
- 106 if (logger.isLoggable(Level.INFO)) {
- 107 logger.info("something is wrong");
- 108 }
- 109 }
- 110 }
- 111 //计算value2
- 112 for (i = 1; i < n; i++) {
- 113 tempValue = a + i * h;
- 114 String code = getSourceCode(expression, getVariable(), Double
- 115 .toString(tempValue));
- 116 try {
- 117 value2 += run(compile(code));
- 118 } catch (Exception e) {
- 119 // TODO Auto-generated catch block
- 120 e.printStackTrace();
- 121 if (logger.isLoggable(Level.INFO)) {
- 122 logger.info("something is wrong");
- 123 }
- 124 }
- 125 }
- 126
- 127 //计算f(a) f(b) 的函数值
- 128 double valueA = getFunctionValue(a);
- 129 double valueB = getFunctionValue(b);
- 130 //计算Simpson公式的值
- 131 double resultValue = (valueA + valueB + 4 * value1 + 2 * value2) * h / 6;
- 132
- 133 return resultValue;
- 134 }
- 135
- 136 //计算F(a) 的值
- 137 private double getFunctionValue(double varValue) {
- 138 String code = getSourceCode(expression, getVariable(), Double
- 139 .toString(varValue));
- 140 double result = 0;
- 141 try {
- 142 result = run(compile(code));
- 143 } catch (Exception e) {
- 144 // TODO Auto-generated catch block
- 145 e.printStackTrace();
- 146 if (logger.isLoggable(Level.INFO)) {
- 147 logger.info("something is wrong");
- 148 }
- 149 }
- 150 return result;
- 151 }
- 152
- 153 /**
- 154 * 得到用户输入表达式转换为Java中的可计算表达式的函数
- 155 * @param ex 输入的表达式 如: 1/(1 + sin(x))
- 156 * @param var 表达式中的变量 如: x
- 157 * @param value 变量的取值 如: 4.3
- 158 * @return Java中可以直接计算的表达式 如: 1/(1 + Math.sin(x))
- 159 */
- 160 private String getSourceCode(String ex, String var, String value) {
- 161 String expression = ex;
- 162 //计算多个变量的函数的时候使用
- 163
- 164 expression = expression.replaceAll(var, value);
- 165
- 166 //处理数学符号
- 167 if (expression.contains(SIN)) {
- 168 expression = expression.replaceAll(SIN, J_SIN);
- 169 } else if (expression.contains(COS)) {
- 170 expression = expression.replaceAll(COS, J_COS);
- 171 } else if (expression.contains(TAN)) {
- 172 expression = expression.replaceAll(TAN, J_TAN);
- 173 } else if (expression.contains(ASIN)) {
- 174 expression = expression.replaceAll(ASIN, J_ASIN);
- 175 } else if (expression.contains(ACOS)) {
- 176 expression = expression.replaceAll(ACOS, J_ACOS);
- 177 } else if (expression.contains(ATAN)) {
- 178 expression = expression.replaceAll(ATAN, J_ATAN);
- 179 } else if (expression.contains(EXP)) {
- 180 expression = expression.replaceAll(EXP, J_EXP);
- 181 } else if (expression.contains(LOG)) {
- 182 expression = expression.replaceAll(LOG, J_LOG);
- 183 } else if (expression.contains(POW)) {
- 184 expression = expression.replaceAll(POW, J_POW);
- 185 } else if (expression.contains(SQRT)) {
- 186 expression = expression.replaceAll(SQRT, J_SQRT);
- 187 } else if (expression.contains(FABS)) {
- 188 expression = expression.replaceAll(FABS, J_FABS);
- 189 }
- 190
- 191 return expression;
- 192 }
- 193
- 194 /** 编译JavaCode,返回java文件*/
- 195 private synchronized File compile(String code) throws Exception {
- 196 File file;
- 197 // 创建一个临时java源文件
- 198 file = File.createTempFile("JavaRuntime", ".java", new File(System
- 199 .getProperty("user.dir")));
- 200 if (logger.isLoggable(Level.INFO)) {
- 201 logger.info(System.getProperty("user.dir"));
- 202 }
- 203 // 当Jvm 退出时 删除该文件
- 204 file.deleteOnExit();
- 205 // 得到文件名和类名
- 206 String filename = file.getName();
- 207 if (logger.isLoggable(Level.INFO)) {
- 208 logger.info("FileName: " + filename);
- 209 }
- 210 String classname = getClassName(filename);
- 211 // 将代码输出到源代码文件中
- 212 PrintWriter out = new PrintWriter(new FileOutputStream(file));
- 213 // 动态构造一个类,用于计算
- 214 out.write("public class " + classname + "{"
- 215 + "public static double main1(String[] args)" + "{");
- 216 out.write("double result = " + code + ";");
- 217 //用于调试
- 218 //out.write("System.out.println(result);");
- 219 out.write("return new Double(result);");
- 220 out.write("}}");
- 221 //关闭文件流
- 222 out.flush();
- 223 out.close();
- 224 //设置编译参数
- 225 String[] args = new String[] { "-d", System.getProperty("user.dir"),
- 226 filename };
- 227 //调试
- 228 if (logger.isLoggable(Level.INFO)) {
- 229 logger.info("编译参数: " + args[0]);
- 230 }
- 231 //Process process = Runtime.getRuntime().exec("javac " + filename);
- 232 int status = Main.compile(args);
- 233 //输出运行的状态码.
- 234 // 状态参数与对应值
- 235 // EXIT_OK 0
- 236 // EXIT_ERROR 1
- 237 // EXIT_CMDERR 2
- 238 // EXIT_SYSERR 3
- 239 // EXIT_ABNORMAL 4
- 240 if (logger.isLoggable(Level.INFO)) {
- 241 logger.info("Compile Status: " + status);
- 242 }
- 243 //System.out.println(process.getOutputStream().toString());
- 244 return file;
- 245 }
- 246
- 247 /**
- 248 * 运行程序 如果出现Exception 则不做处理 抛出!
- 249 * @param file 运行的文件名
- 250 * @return 得到的Simpson积分公式的结果
- 251 * @throws Exception 抛出Exception 不作处理
- 252 */
- 253 private synchronized double run(File file) throws Exception {
- 254 String filename = file.getName();
- 255 String classname = getClassName(filename);
- 256 Double tempResult = null;
- 257 // System.out.println("class Name: " +classname);
- 258 //当Jvm 退出时候 删除生成的临时文件
- 259 new File(file.getParent(), classname + ".class").deleteOnExit();
- 260 try {
- 261 Class cls = Class.forName(classname);
- 262 //System.out.println("run........");
- 263 // 映射main1方法
- 264 Method calculate = cls
- 265 .getMethod("main1", new Class[] { String[].class });
- 266 //执行计算方法 得到计算的结果
- 267 tempResult = (Double) calculate.invoke(null,
- 268 new Object[] { new String[0] });
- 269 } catch (SecurityException se) {
- 270 System.out.println("something is wrong !!!!");
- 271 System.out.println("请重新运行一遍");
- 272 }
- 273 //返回值
- 274 return tempResult.doubleValue();
- 275 }
- 276
- 277 /** 调试函数*/
- 278 // private void debug(String msg) {
- 279 // System.err.println(msg);
- 280 // }
- 281
- 282 /** 得到类的名字 */
- 283 private String getClassName(String filename) {
- 284 return filename.substring(0, filename.length() - 5);
- 285 }
- 286
- 287
- 288 //getter and setter
- 289 public String getExpression() {
- 290 return expression;
- 291 }
- 292
- 293 public void setExpression(String expression) {
- 294 this.expression = expression;
- 295 }
- 296
- 297 public String getVariable() {
- 298 return variable;
- 299 }
- 300
- 301 public void setVariable(String variable) {
- 302 this.variable = variable;
- 303 }
- 304
- <spa>