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

相關推薦

利用Java動態編譯計算數學表示式

前幾天要做一個計算數學表示式的題目,本來計劃使用解析表示式的方法來解析各種數學表示式,然後再動態計算表示式的值.後來考慮到這樣程式設計的任務很重,時間有限 後來在網上搜搜,看到使用動態編譯並使用反射機制 ,這樣計算表示式的程式設計就容易多了.下面是我這次程式設計的例子, 請大

java 動態編譯

runtime {} runt mpi src lan provider null roc 1.第一種方式:JavaCompiler+Runntime public static void run() { JavaCompiler compiler

Java動態編譯動態載入詳解

一.動態編譯 在某些情況下,我們需要動態生成java程式碼,通過動態編譯,然後執行程式碼。JAVA API提供了相應的工具(JavaCompiler)來實現動態編譯。 //獲取JavaCompiler JavaCompiler compiler = ToolProvider.getSyste

[bash]判斷三角形型別、計算數學表示式計算N個整數的指定精度的平均值

判斷三角形為等邊三角形、等腰三角形或不等邊三角形 #!/bin/bash #https://www.hackerrank.com/challenges/bash-tutorials---more-on-conditionals/problem read a read b read c

java動態編譯class,動態載入類,執行載入類的方法,直接可執行測試

直接上圖上程式碼 public static void main(String[] args) { TestClass testClass=new TestClass(); try { //動態編譯程式碼 Java

java動態編譯java線上執行程式碼後端實現原理)

需求:要實現一個web網頁中輸入java程式碼,然後能知道編譯結果以及執行結果 類似於菜鳥java線上工具的效果:https://c.runoob.com/compile/10 剛開始從什麼概念都沒有到最後封裝成一個完整的工具類,中間查閱了很多資料才瞭解其中的概念以及流程,參考文獻在文章最後面。 重點需要

Java動態編譯優化——提升編譯速度(N倍)

一、前言 最近一直在研究Java8 的動態編譯, 並且也被ZipFileIndex$Entry 記憶體洩漏所困擾,在無意中,看到一個第三方外掛的動態編譯。並且編譯速度是原來的2-3倍。原本打算直接用這個外掛,但是發現外掛的編譯原始碼存在我之前已經解決過的記憶體洩漏問題。所以拿其原始碼,進行改

Java動態編譯優化——ZipFileIndex記憶體洩漏問題分析解決

一、前言: 前幾天解決了URLClassLoader記憶體洩漏的問題,但是解決問題就像剝洋蔥,剝去了外層,內層 問題又暴露出來了。當URLClassLoader記憶體洩漏解決, 需要解決的就是ZipFileIndex記憶體洩漏的問題了,而且這個問題折騰了我2天半的時間。 URLClass

Java動態編譯優化——URLClassLoader 記憶體洩漏問題解決

一、動態編譯案例 要說動態編譯記憶體洩漏,首先我們先看一個案例(網上搜動態編譯的資料是千篇一律,只管實現功能,不管記憶體洩漏,並且都恬不知恥的標識為原創!!) Java  URLClassLoader 動態編譯案例:https://blog.csdn.net/huangshan

JVM調優——Java動態編譯過程中的記憶體溢位問題

由於測試環境專案每2小時記憶體就溢位一次, 分析問題,發現Java動態載入Class並執行那塊存在記憶體溢位問題, 遂本地調測。 一、找到動態編譯那塊的程式碼,具體如下 /** * @MethodName : 編譯java程式碼到Object * @Descrip

利用Java裡的正則表示式求一群人身份證上的出生年月日

package Regex; import java.util.regex.*; import java.util.regex.Matcher; public class testIdCard { public static void main(String[] ar

利用Java 動態代理,自定義註解 讀取配置檔案中的屬性值

Java動態代理在一些中介軟體中經常用到,或者一些大型專案中都會用到。 這裡順帶使用一下自定義註解方式,基於java 反射機制讀取.properties格式檔案。 demo的大致內容包含以下: 1.配置檔案:config.properties url=http://www.

Groovy&Java動態編譯執行

工作中,遇到部分業務經常動態變化,或者在不釋出系統的前提下,對業務規則進行調整。那麼可以將這部分業務邏輯改寫成Groovy指令碼來執行,那麼就可以在業務執行過程中動態更改業務規則,達到快速響應。 Case1: Groovy動態編譯執行 閒話少說,直接上程式碼: stati

【Big Data 每日一題20180822】Java動態編譯優化——URLClassLoader 記憶體洩漏問題解決

一、動態編譯案例 要說動態編譯記憶體洩漏,首先我們先看一個案例(網上搜動態編譯的資料是千篇一律,只管實現功能,不管記憶體洩漏,並且都恬不知恥的標識為原創!!) 這篇文章和我google搜的其他文章、資料一樣,屬於JDK1.6以後的版本。確實能實現動態編譯並載入,但

Java 動態編譯時出現空指標異常

如題:問題原因檢視該播客:http://www.cnblogs.com/fangwenyu/archive/2011/10/12/2209051.html解決方法就是將java/jdk/tools.jar檔案拷貝到java/jre/lib下面。我安裝java的時候將檔案分開了

java 動態編譯&load

有時候我們需要把一些外部資源(比如第三方jar,自己動態生成的java檔案)編譯並載入到classloader,這時我們就需要JavaCompiler 個類,jdk是從1.6開始支援此功能 網上有很多類似列子,搜尋“動態編譯”可以找到,我這裡只列出一種實現方法

Java動態編譯

code rgs pac 工程 tool getname rri n) tac Java動態編譯 最近熟悉了一下反射,對Java的動態性有了進一步的了解,因此想實現一下用Java直接動態生成.class文件,也就是在編譯完成後,運行時編譯java文件 工程結構 ? hel

利用Java動態編譯動態載入結合EasyRules實現業務規則的動態性

作為一名專門寫bug的Java程式猿,相信大家都會遇到過這樣的問題:專案的業務邏輯很複雜,而且還經常變化,今天的一個辦理條件是小於5,明天就變成了大於10或者條件作廢。這就很頭疼了,裡面的數字可以抽取到配置檔案,但是大於和小於呢?條件作廢呢? 對於業務規則的複雜性,我們可以使用一些規則引擎來

利用javax.tools動態編譯執行java程式碼

  javax.tools 包是一種新增到 Java SE 6 的標準 API,可以實現 Java 原始碼編譯,使您能夠新增動態功能來擴充套件靜態應用程式。本文將探查javax.tools包中提供的主要類,以Java表示式表示計算一個數值函式y=x*x+x。更多詳情請參

java利用動態編譯實現eval

我們知道,在很多指令碼語言中都有eval涵數,它可以把字串轉換為表態式並執行.如在javaScript中var str = aid.value + ".style.top = 10;"把一個id為"aid"的控制的值取出來加合併成一個字串,如果aid的值是"axman",則s