`

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

    博客分类:
  • JAVA
阅读更多

前几天要做一个计算数学表达式的题目,本来计划使用解析表达式的方法来解析各种数学表达式,然后再动态计算表达式的值.后来考虑到这样编程的任务很重,时间有限 后来在网上搜搜,看到使用动态编译并使用反射机制 ,这样计算表达式的编程就容易多了.下面是我这次编程的例子, 请大家看看.

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

相关推荐

    java范例开发大全源代码

    第1篇 Java编程基础  第1章 Java开发环境的搭建(教学视频:9分钟) 2  1.1 理解Java 2  1.2 搭建Java所需环境 3  1.2.1 下载JDK 3  1.2.2 安装JDK 4  1.2.3 配置环境 5  1.2.4 测试JDK配置...

    java范例开发大全

    第1篇 Java编程基础 第1章 Java开发环境的搭建(教学视频:9分钟) 2 1.1 理解Java 2 1.2 搭建Java所需环境 3 1.2.1 下载JDK 3 1.2.2 安装JDK 4 1.2.3 配置环境 5 1.2.4 测试JDK配置是否成功 7 实例1 开发第一个Java...

    Java范例开发大全 (源程序)

    第1篇 Java编程基础  第1章 Java开发环境的搭建(教学视频:9分钟) 2  1.1 理解Java 2  1.2 搭建Java所需环境 3  1.2.1 下载JDK 3  1.2.2 安装JDK 4  1.2.3 配置环境 5  1.2.4 测试JDK配置是否成功 7...

    Java范例开发大全(全书源程序)

    Java范例开发大全(全书源程序),目录如下: 第1篇 Java编程基础 第1章 Java开发环境的搭建(教学视频:9分钟) 2 1.1 理解Java 2 1.2 搭建Java所需环境 3 1.2.1 下载JDK 3 1.2.2 安装JDK 4 1.2.3 配置环境...

    java范例开发大全(pdf&源码)

    第1篇 Java编程基础 第1章 Java开发环境的搭建(教学视频:9分钟) 2 1.1 理解Java 2 1.2 搭建Java所需环境 3 1.2.1 下载JDK 3 1.2.2 安装JDK 4 1.2.3 配置环境 5 1.2.4 测试JDK配置是否成功 7 实例1 开发第一个Java...

    javaSE代码实例

    14.8.3 利用栈计算数学表达式 311 14.9 集合元素的常用操作 314 14.9.1 元素排序 315 14.9.2 搜索特定元素 316 14.9.3 任意打乱元素顺序 317 14.9.4 其他的简单操作 318 14.10 小结 320 第15章 内部...

    C++大学教程,一本适合初学者的入门教材(part2)

    1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的...

    C++大学教程,一本适合初学者的入门教材(part1)

    1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的...

    Tcl_TK编程权威指南pdf

    数学表达式 反斜杠替换 使用花括号和双引号进行分组 过程 一个阶乘的例子 更多有关变量的知识 更多有关数学表达式的内容 注释 有关替换与分组的总结 要点 参考 第2章 开始使用 source命令 unix上的tcl...

Global site tag (gtag.js) - Google Analytics