您的位置:首页技术文章
文章详情页

利用Java动态编译计算数学表达式

【字号: 日期:2024-06-16 17:46:54浏览:2作者:猪猪
内容: 前几天要做一个计算数学表达式的题目,本来计划使用解析表达式的方法来解析各种数学表达式,然后再动态计算表达式的值.后来考虑到这样编程的任务很重,时间有限 后来在网上搜搜,看到使用动态编译并使用反射机制 ,这样计算表达式的编程就容易多了.下面是我这次编程的例子, 请大家看看.01 /*02 * Created on 2006-3-803 * @author icerain 我的Blog: http://blog.matrix.org.cn/page/icess04 */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-7003 * @author icerain 我的Blog: http://blog.matrix.org.cn/page/icess004 */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) 而不要写为 sinx021 * 3.在两个数或者变量相乘时候,不要省略乘号* 如:2*a 不要写为 2a022 * 4.在写幂运算的时候,请使用如下格式: 023 * 利用动态编译来计算Simpson积分,使用该方法 编程相对简单,运行效率有点慢.024 * @author icerain025 *026 */027 public class Simpson implements IOperator {028 /**029 * Logger for this class030 */031 private static final Logger logger = Logger.getLogger(Simpson.class032 .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 //计算value1096 for (i = 0; i < n; i++) {097 tempValue = a + (i + 0.5) * h;098 String code = getSourceCode(expression, getVariable(), Double099 .toString(tempValue));100 try {101 value1 += run(compile(code));102 } catch (Exception e) {103 // TODO Auto-generated catch block104 e.printStackTrace();105 106 if (logger.isLoggable(Level.INFO)) {107 logger.info('something is wrong');108 }109 }110 }111 //计算value2112 for (i = 1; i < n; i++) {113 tempValue = a + i * h;114 String code = getSourceCode(expression, getVariable(), Double115 .toString(tempValue));116 try {117 value2 += run(compile(code));118 } catch (Exception e) {119 // TODO Auto-generated catch block120 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(), Double139 .toString(varValue));140 double result = 0;141 try {142 result = run(compile(code));143 } catch (Exception e) {144 // TODO Auto-generated catch block145 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 表达式中的变量 如: x157 * @param value 变量的取值 如: 4.3158 * @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(System199 .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 4240 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 = cls265 .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 setter289 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 305 public String[] getVariableValue() {306 return variableValue;307 }308 309 public void setVariableValue(String[] variableValue) {310 this.variableValue = variableValue;311 }312 } 这样就可以用来计算了.下面编写一个.bat文件来运行改程序.(在这里没有打包为.jar文件)@echo 注意:@echo ***********************************************************@echo * 利用Simpson公式计算积分,在输入被积公式时候请注意使用 ***@echo * 如下格式. ***@echo * 1.只使用圆括号() , 没有别的括号可以使用.如: ***@echo * 1/(1+sin(x)) ***@echo * 2.在输入超越函数的时候,变量和数值用括号扩起来 如: ***@echo * sin(x) 而不要写为 sinx ***@echo * 3.在两个数或者变量相乘时候,不要省略乘号* 如: ***@echo * 2*a 不要写为 2a ***@echo * 4.在写幂运算的时候,请使用如下格式: ***@echo * pow(x,y) 代表x的y次幂 不要使用其他符号 ***@echo * 5.绝对值请用如下符号表示: ***@echo * fabs(x) 代表x的绝对值 ***@echo * 6.指数函数请用exp表示 如:exp(x) ***@echo * 7.对数函数请用log(x)表示, 该处对数是指底为10的对数, ***@echo * 计算不是以10为底的对数时候请转换为10为底的对数 ***@echo * 8.变量字符请不要与函数中的其他字符重合,如 如果使用了 ***@echo * sin 函数请 不要用 s i 或者n做为变量,否则在解析 ***@echo * 表达式时候 会出错 ^_^@echo *********************************************************** @Rem 在编译源文件时候 要使用下面的命令 把rem 删除即可 注意 由于文件中用到了tools.jar中@rem 的命令 所有在编译的时候 用适当的classpath 替换下面的 tools.jar的路径 运行的时候一样@rem javac -classpath '.;D:Program FilesJavajdk1.5.0_03libtools.jar;%CLASSPATH%' Simpson.java %1@rem 注意更改此处的tools.jar的路径 为你当前系统的正确路径@java -cp '.;D:Program FilesJavajdk1.5.0_03libtools.jar' Simpson@Pause  这样就可以了.说明:使用该方法来计算本程序,由于要多次动态产生计算源代码,并且编译 在性能上会有很大损失. 要是在项目中不经常计算表达式 使用该方法可以减轻编程的负担.要是象上面那样 要多次计算的话,使用该方法是很值得考虑的. Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd 前几天要做一个计算数学表达式的题目,本来计划使用解析表达式的方法来解析各种数学表达式,然后再动态计算表达式的值.后来考虑到这样编程的任务很重,时间有限 后来在网上搜搜,看到使用动态编译并使用反射机制 ,这样计算表达式的编程就容易多了.下面是我这次编程的例子, 请大家看看.01 /*02 * Created on 2006-3-8
标签: Java
相关文章: