`

利用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实现计算字符串表达式

    这篇博客“Java实现计算字符串表达式”可能讲解了如何利用Java来处理这种问题,虽然具体的实现细节没有提供,但我们可以基于一般的方法和常用的库来探讨这个主题。 首先,计算字符串表达式的基本步骤通常包括以下几...

    Android 计算数学表达式(NDK JNI方式)

    在Android开发中,有时我们需要处理复杂的数学计算,例如解析和计算数学表达式。为了提高性能,我们可以使用Native Development Kit (NDK) 和Java Native Interface (JNI) 来实现。本教程将详细介绍如何通过NDK和JNI...

    java 写的 用优先函数分析 数学表达式的程序

    在这个“java 写的 用优先函数分析 数学表达式的程序”中,我们将深入探讨如何使用Java来解析和计算数学表达式,以及涉及的编译原理知识。 首先,我们需要理解什么是数学表达式分析。在计算机科学中,解析数学...

    qlexpress java表达式

    《QLEXPRESS Java表达式解析与应用》 在Java编程中,表达式扮演着至关重要的角色,它们是程序逻辑的基础。...通过深入理解和熟练运用QLEXPRESS,我们能够更好地利用Java表达式的威力,提升软件的可维护性和可扩展性。

    编译原理表达式计算器

    "编译原理表达式计算器"是一个基于C#编程语言实现的计算工具,它能够处理包含加、减、乘、除、括号以及取负等基本数学运算的表达式。这个程序利用了编译原理中的核心概念,如词法分析和算符优先分析,来解析并计算...

    Aviator是一个高性能java表达式求值程序

    3. **配置中心**:在微服务架构中,服务的配置可以通过Aviator表达式动态设定,提高配置的灵活性。 4. **脚本语言替代**:对于一些简单的脚本需求,Aviator可以作为Java的轻量级替代方案。 总的来说,Aviator作为...

    java实现的表达式计算器

    本文将深入探讨一个基于Java实现的表达式计算器项目,旨在帮助开发者理解如何在Java环境中设计和实现一个能解析并计算数学表达式的程序。 首先,我们来看“java实现的表达式计算器”这个标题,它揭示了我们的任务是...

    ExpGen:Java随机数学表达式生成器

    ExpGen利用了Java的强大功能,实现了数学表达式的动态生成。在数学表达式生成方面,ExpGen可能包含以下核心特性: 1. **随机数生成**:ExpGen能够生成随机的数值,包括整数和浮点数,这些数值可以作为表达式的一...

    JAVA表达工计算工具PARSII

    PARSII可能提供了诸如表达式树、令牌解析、语法分析等技术,这些都是编译原理中的概念,用于将字符串形式的数学表达式转化为可执行的计算步骤。它可能还包括错误处理机制,当用户输入的表达式有误时,能够提供清晰的...

    利用正则式计算表达式的值

    `Calculate.java`可能实现了一个解析器,这个解析器使用正则表达式将输入的数学表达式转换为可执行的形式。解析过程中,可能包括以下几个步骤: 1. **预处理**:清理输入,去除无关的空格和符号,处理括号以确保...

    基于Java语言编写的计算器表达式分析器其中包括词法分析和语法分析部分.zip

    总之,这个基于Java的计算器表达式分析器项目涵盖了编译原理的核心概念,通过词法分析和语法分析,实现了对数学表达式的有效处理。开发者可以利用这个工具来学习编译器设计,或者将其整合到自己的应用程序中,以处理...

    表达式计算器小程序

    本项目旨在通过实现一个能够处理数学表达式的计算器小程序,深化对编译原理的理解,并熟练掌握相关编程技巧。特别是,该程序强调了优先级算法的实现以及对负数计算的支持,这两大特性不仅体现了程序设计的复杂性,也...

    表达式引擎fel-0.9版本

    在0.9版本中,它提供了强大的动态计算功能,使得开发者能够在运行时评估复杂的逻辑和数学表达式。这个版本的发布,旨在提升应用程序的灵活性,特别是对于那些需要动态数据处理和决策逻辑的应用场景。 Fel引擎的核心...

    中缀表达式转后缀表达式

    中缀表达式是我们日常生活中常见的数学表达式形式,比如2 + 3 * 4,其中运算符位于操作数之间。而后缀表达式,也称为逆波兰表示法,将运算符置于操作数之后,如2 3 4 * +,它在计算时无需括号,通过栈数据结构即可...

    Java命令行实现简单的计算器

    在实现这个计算器程序的过程中,你将学习到如何在命令行下与用户交互,如何解析和处理复杂的数学表达式,以及如何在Java中实现错误处理。这是一项有助于提升你编程技能的练习,同时也会让你对Java的面向对象编程有更...

    java带界面的计算器

    通过这个项目,开发者可以深入理解Java编程、GUI设计、事件处理以及数学表达式的解析与计算。无论是对于初学者还是有经验的程序员,这样的练习都能提供宝贵的学习机会,提升编程技能和问题解决能力。

    java解析公式 eval.jar

    Java解析公式库`eval.jar`是一个专门为Java开发者设计的开源工具,它允许程序在运行时动态解析和执行数学表达式。这个库的核心功能是提供一个简单、高效的接口,用于处理包含加法(+)、减法(-)、乘法(*)、除法...

    Java正则表达式详解

    无论是编程语言还是文本编辑器,广泛地利用正则表达式来实现高级的功能。 **1.1 正则表达式的起源与发展** 正则表达式的概念起源于20世纪50年代,由美国数学家斯蒂芬·科恩(Stephen Cole Kleene)提出,并在后来的...

    后缀表达式实现的计算器

    后缀表达式实现的计算器是一种基于栈数据结构的计算工具,能够有效地解析和计算数学表达式。下面我们将深入探讨后缀表达式的原理、计算过程以及如何用源代码实现一个计算器。 1. 后缀表达式原理 后缀表达式是将...

Global site tag (gtag.js) - Google Analytics