java的代数方程解析器

问题描述 投票:17回答:5

我需要一个库来解析方程式,给出输入结果。

例如这样的事情:

String equation = "x + y + z";
Map<String, Integer> vars = new HashMap<String, Integer>();
vars.add("x", 2);
vars.add("y", 1),
vars.add("z", 3);
EquationSolver solver = new EquationSolver(equation, vars);
int result = solver.getResult();
System.out.println("result: " + result);

并评估为:6

是否有任何类型的java库可以为我做到这一点?

谢谢

java equation algebra
5个回答
28
投票

您可以使用Java 1.6的脚本功能:

import javax.script.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
        Map<String, Object> vars = new HashMap<String, Object>();
        vars.put("x", 2);
        vars.put("y", 1);
        vars.put("z", 3);
        System.out.println("result = "+engine.eval("x + y + z", new SimpleBindings(vars)));
    }
}

产生:

result = 6.0

对于更复杂的表达方式,JEP是一个不错的选择。


17
投票

还有exp4j,一个基于Dijkstra的Shunting Yard的表达式评估器。它是Apache License 2.0下免费提供和可再发行的,只有25kb,非常易于使用。

Calculable calc = new ExpressionBuilder("3 * sin(y) - 2 / (x - 2)")
        .withVariable("x", varX)
        .withVariable("y", varY)
        .build()
double result1=calc.calculate();

还有一个设施可以在exp4j中使用自定义功能。

exp4j - evaluate math expressions

玩得开心!


2
投票

如果你想要高性能,我建议不要使用exp4j,因为CogitoLearning类比exp4j快了大约2600倍(在1万次迭代上测试),是的你读得对。

通常,简单表达式足以满足业务应用程序的需要。因此,CogitoLearning创建的库可能是更好的选择。

基准测试结果:

1000000 iterations to evaluate 200*(1+(pi/2))^2
Time Exp4J: 1.041117999977863E-5
Time JavaScript:4.532046999924487E-5 - 0.2297235664138545x slower than Exp4j
Time ExpCogit:  4.0000000000000036E-9 - 2602.794999944655x faster than Exp4j

对于Cogito库,请参阅http://cogitolearning.co.uk/docs/cogpar/index.html

请注意:测试用例并不完全纯粹用于评估JavaScript性能,因为我没有使用预构建表达式来处理该情况。

使用的基准代码:

public class TestParser {
    private static String exprStr = "200*(1+(pi/2))^2";

    /**
     * Exp4j
     */ 
    private static ExpressionBuilder eb =  new ExpressionBuilder(exprStr);

    /**
     * Cogit
     */
    private static Parser parser = new Parser();
    private static ExpressionNode expr = parser.parse(exprStr);

    /**
     * JavaScript 
     */
    private static ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
    private static Map<String, Object> vars = new HashMap<String, Object>();

    public static void main(String[] args) throws UnknownFunctionException, UnparsableExpressionException, ScriptException {
        int n = 1000000;

        double t1 = 0d; 
        for(int i=1; i!=n; i++) {
            t1+=getCalcTimeExp4J();
        }
        double r1=t1/n;

        double t2 = 0d; 
        for(int i=1; i!=n; i++) {
            t2+=getCalcTimeCogit();
        }
        double r2=t2/n;

        double t3 = 0d; 
        for(int i=1; i!=n; i++) {
            t3+=getCalcTimeJavaScriptEngine();
        }
        double r3=t3/n;     

        System.out.println(n + " iterations to evaluate " + exprStr);
        System.out.println("Time Exp4J:\t" + r1);

        System.out.println("Time JavaScript:" + r3 + " - " + r1/r3 + "x slower than Exp4j");
        System.out.println("Time ExpCogit:\t" + r2 + " - " + r1/r2 + "x faster than Exp4j");

    }

    private static double getCalcTimeJavaScriptEngine() throws ScriptException {
        long t = Util.nanotime();

        vars.put("pi", Math.PI); 
        //Note that we're actually not using a pre-build expression here.
        engine.eval(exprStr, new SimpleBindings(vars)); 

        return(Util.nanotimeToSeconds(t));
    }

    private static double getCalcTimeCogit() {
        long t = Util.nanotime();

        expr.accept(new SetVariable("pi", Math.PI));
        double r = expr.getValue();

        return(Util.nanotimeToSeconds(t));
    }           

    private static double getCalcTimeExp4J() throws UnknownFunctionException, UnparsableExpressionException {
        long t = Util.nanotime();
        Calculable calc = eb.withVariable("pi", Math.PI).build();
        double r = calc.calculate();

        return(Util.nanotimeToSeconds(t));
    }
}

1
投票

试试mXparser,下面你会看到用法示例:

import org.mariuszgromada.math.mxparser.*;
...
...
String equation = "x + y + z";
Argument x = new Argument("x = 2");
Argument y = new Argument("y = 1");
Argument z = new Argument("z = 3");
Expression solver = new Expression(equation, x, y, z);
double result1 = solver.calculate();
System.out.println("result 1: " + result1);
x.setArgumentValue(3);
y.setArgumentValue(4);
z.setArgumentValue(5);
double result2 = solver.calculate();
System.out.println("result 2: " + result2);

结果:

result 1: 6.0
result 2: 12.0

这里mXparser的优点是mXparser只预编译一次表达式,然后,在参数值改变之后,计算速度非常快。

关注qazxsw poi,qazxsw poi,qazxsw poi。

问候


0
投票

从问这个问题开始的未来八年:如果你不想重新发明轮子,那里有许多奇特的数学解析器。

我在几年前写过一篇文章,它支持算术运算,方程求解,微积分,积分微积分,基本统计,函数/公式定义,图形等。

它被称为mXparser tutorial及其开源。

评估表达式非常简单:

mXparser math collection

或者使用变量并计算简单表达式:

mXparser API

或使用功能:

ParserNG

或者评估给定点的导数(注意它在幕后进行符号微分(非数值),因此精度不受数值近似误差的限制):

    MathExpression expr = new MathExpression("(34+32)-44/(8+9(3+2))-22"); 
    System.out.println("result: " + expr.solve());

    result: 43.16981132075472

这在q = 3时区分 MathExpression expr = new MathExpression("r=3;P=2*pi*r;"); System.out.println("result: " + expr.getValue("P")); 一次。您可以区分的次数是1。

或用于数值积分:

MathExpression expr = new MathExpression("f(x)=39*sin(x^2)+x^3*cos(x);f(3)"); 
System.out.println("result: " + expr.solve());

result: -10.65717648378352

这个解析器速度非常快,并且具有许多其他功能。

免责声明:ParserNG由我撰写。

© www.soinside.com 2019 - 2024. All rights reserved.