zoukankan      html  css  js  c++  java
  • 利用Java动态编译计算数学表达式 简单飞扬

    摘自网络


    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

     

    这样就可以了.

    说明:

    使用该方法来计算本程序,由于要多次动态产生计算源代码,并且编译 在性能上会有很大损失. 要是在项目中不经常计算表达式 使用该方法可以减轻编程的负担.要是象上面那样 要多次计算的话,使用该方法是很值得考虑的.

  • 相关阅读:
    一个奇怪的网页bug 竟然是局域网DNS搞的鬼
    繁体系统下如何快速将简体安装文件乱码恢复正常?
    Ubuntu16.04LTS国内快速源
    bitnami redmine版本由2.3.1升级至3.2.2过程
    Ubuntu1404安装gogs过程
    AJAX
    jQuery 事件解释
    安装phpMyadmi报错
    总结二
    总结
  • 原文地址:https://www.cnblogs.com/jiandanfy/p/1360060.html
Copyright © 2011-2022 走看看