您的位置:首页 > 编程语言 > Java开发

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

2008-12-22 20:18 627 查看
摘自网络

01 /*

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

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 Files\Java\jdk1.5.0_03\lib\tools.jar;%CLASSPATH%" Simpson.java %1

@rem 注意更改此处的tools.jar的路径 为你当前系统的正确路径

@java -cp ".;D:\Program Files\Java\jdk1.5.0_03\lib\tools.jar" Simpson

@Pause

 

这样就可以了.

说明:

使用该方法来计算本程序,由于要多次动态产生计算源代码,并且编译 在性能上会有很大损失. 要是在项目中不经常计算表达式 使用该方法可以减轻编程的负担.要是象上面那样 要多次计算的话,使用该方法是很值得考虑的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: