科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道大数据的情况下如何高效的计算表达式的值

大数据的情况下如何高效的计算表达式的值

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

大数据的情况下如何高效的计算表达式的值

作者:csdn 来源:csdn 2009年12月17日

关键字: 问答 JavaSE java

  • 评论
  • 分享微博
  • 分享邮件

大数据的情况下如何高效的计算表达式的值

最近的一个项目需要进行蒙特卡洛模拟,并且需要对模拟结果进行表达式求职计算
计算的公式不固定一般的格式是这样$0+$1*2/$3*2.5且随着业务的复杂还需要
进行多次迭代计算。数据量很大最少的也要进行2-3万次计算。

我试了用自己写的表达式求职程序和Mozilla的Rhino效率上都不是很理想,可能是自己
水平比较差,用Mozilla的Rhino居然比自己写的程序快一倍。我们用的jdk1.5所以不能
用jdk1.6中才支持的编译后执行脚本的方法。

想过尝试动态生成Java文件然后编译执行,但是一想起在服务器环境这个程序可能需要
同时计算多个表达式......越想越觉得不可靠.

 

以脚本语言的计算能力根本就不适合做大规模数值计算。
你可以先把一个固定的计算公式用java写好,然后跟Rhino比较一下。保守的估计至少要差几十倍以上,rhino的脚本编译运行也不能提高太多的效率,因为它依旧要依靠脚本运行引擎。
如果计算公式不是经常变化的话,还是可以用java写,用javac动态编译。同时可以考虑用文件保存编译过的class。

 

哈哈,我终于知道前面为什么要 600ms 了,因为我多做了几次循环,哎,真粗心!

改正后实际的工作时间在 150ms 左右(由于 JDK 的初始化问题,测试三次使用平均数)。有两种实现方式:

第一种方法:
Java codeimport java.util.Random;

import bsh.EvalError;
import bsh.Interpreter;

public class Test2 {
   
    public static void main(String[] args) throws EvalError {       
        final int count = 5000;
        final int paramCount = 4;
       
        double[][] datas = new double[paramCount][count];
        random(datas);
        double[] results = new double[count];
       
        long t0, t1;      
        String exp = "$0 + $1 * $2 + $3";
        t0 = System.currentTimeMillis();
        eval(exp, results, datas);       
        t1 = System.currentTimeMillis();
        System.out.println(t1 - t0);
        testCorrect(results, datas);
       
        random(datas);
        t0 = System.currentTimeMillis();
        eval(exp, results, datas);       
        t1 = System.currentTimeMillis();
        System.out.println(t1 - t0);
        testCorrect(results, datas);
       
        random(datas);
        t0 = System.currentTimeMillis();
        eval(exp, results, datas);       
        t1 = System.currentTimeMillis();
        System.out.println(t1 - t0);
        testCorrect(results, datas);
    }
   
    public static void eval(String expression, double[] results, double[]... datas) throws EvalError {
       
        String ep = expression.replaceAll("\\$(\\d+)", "datas[$1][j]");
       
        String exp =
            "for(int j = 0, k = datas[0].length; j < k; j++) {" +
            "  results[j] = " + ep + ";" +
            "}";
        Interpreter bsh = new Interpreter();
        bsh.set("datas", datas);
        bsh.set("results", results);
        bsh.eval(exp);
        results = (double[])bsh.get("results");
    }
   
    /**
     * 随机生成数据值
     *
     * @param datas
     */
    private static void random(double[][] datas) {
        Random ran = new Random();
        for(int i = 0; i < datas.length; i++) {
            for(int j = 0; j < datas[i].length; j++) {
                datas[i][j] = ran.nextDouble() * datas[i].length;
            }
        }
    }
   
    /**
     * 测试调用的结果是否正确
     * @param results
     * @param datas
     */
    private static void testCorrect(double[] results, double[][] datas) {
        double[] res = new double[results.length];
        for(int j = 0; j < datas[0].length; j++) {
           for(int i = 0; i < datas.length; i++) {
               res[j] = datas[0][j] + datas[1][j] * datas[2][j] + datas[3][j];
           }
        }       
        for(int i = 0; i < results.length; i++) {
            if(results[i] != res[i]) {
                System.out.printf("error! %.6f --> %.6f%n", results[i], res[i]);
            }
        }
    }
}


第二种方法,只是更改 eval 方法,使用字符串更像一个 Java 方法:

Java code    public static void eval(String expression, double[] results, double[]... datas) throws EvalError {
        String ep = expression.replaceAll("\\$(\\d+)", "datas[$1][j]");       
        String exp =
            "public void eval(double[] results, double[][] datas) {" +
            "  for(int j = 0, k = datas[0].length; j < k; j++) {" +
            "    results[j] = " + ep + ";" +
            "  }" +
            "}";
        Interpreter interpreter = new Interpreter();
        NameSpace ns = NameSpace.JAVACODE;
        interpreter.eval(exp, ns);
        BshMethod method = ns.getMethods()[0];
        method.invoke(new Object[]{ results, datas }, interpreter);       
    }

 



    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章