【问题标题】:Algebra equation parser for javajava的代数方程解析器
【发布时间】:2011-01-13 15:46:22
【问题描述】:

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

例如这样的:

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 可以评估2+1+3。因此,除非您尝试进行高级数学运算,否则它实际上只是一些字符串操作,然后让 java 评估等式。除非我误解了你的问题。
  • @Dartoxian - 编写一个处理多种简单格式以外的任何东西的方程解析器实际上非常困难
  • 我试图在我的应用程序中定义一些公式,以便通过一些外部属性动态更改它。例如,也许今天我的公式只是“x + y + z”,但有人可能想将其更改为“x ^ 2 * y / z”。
  • 其实并不难。您转换为后缀表示法,然后使用堆栈进行计算。我记得必须将其作为学习 lex/yacc 的家庭作业。

标签: java equation algebra


【解决方案1】:

您可以利用 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 是一个不错的选择。

【讨论】:

  • 很好的解决方案。我同意我认为他所要做的就是进行一些字符串操作,然后评估结果。不过,我不知道您可以轻松做到这一点:) +1
  • 我也尝试了一段时间,但作为 javascript 表达式进行评估非常非常慢。因此,如果您要进行大量计算,这可能不是最好的解决方案
  • 感谢您为我编写方程解析器节省了大量时间;尽管 Nashorn JavaScript 引擎在 JDK 15 及更高版本中已从 Java 中删除,但我仍然可以使用其他 JavaScript 引擎,例如 Mozilla Rhino,它是 JDK 8 引入 Nashorn 之前的默认 JavaScript 引擎。
【解决方案2】:

还有exp4j,一个基于 Dijkstra 的 Shutting Yard 的表达式评估器。它在 Apache 许可证 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

玩得开心!

【讨论】:

  • 一条建议:不要一遍又一遍地发布相同的答案来宣传您的图书馆,因为这可能会让人讨厌,并且会被标记为垃圾邮件。如果它真的很好,您根本不需要这样做,您的快乐用户会为您传播信息。干杯。
  • 我很好地回答了问题,在我看来这不是垃圾邮件,即使相同的答案适用于不同的问题。还是您认为答案断章取义,没有帮助?
  • 我只是警告您,此答案已被标记为重复内容。而且由于您显然不是垃圾邮件发送者,因此我认为您被贴上这样的标签会很遗憾。问候。
  • 这不是断章取义。谢谢。
【解决方案3】:

试试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只预编译一次表达式,然后参数值改变后,计算速度非常快。

关注mXparser tutorialmXparser math collectionmXparser API

另外 - 这个软件也使用 mXparser - 你可以学习语法 Scalar Calculator app

问候

【讨论】:

    【解决方案4】:

    如果你想要高性能,我建议不要使用 exp4j,因为 CogitoLearning 类比 exp4j 快大约 2600 倍(经过 100 万次迭代测试),是的,你没看错。

    通常,对于业务应用程序来说,简单的表达式就足够了。因此,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));
        }
    }
    

    【讨论】:

    • 注意:exp4j 在这种情况下很慢,因为表达式是在每次迭代期间构建的。如果设置正确,exp4j 在求解大型方程时比 Cogito 更快,这些方程在每次评估迭代期间具有多个变量且值会发生变化/更新。
    • 你能分享进口吗?
    【解决方案5】:

    从被问到这个问题的八年后:如果您不想重新发明轮子,那里有许多奇特的数学解析器。

    我多年前写过一个,它支持算术运算、方程求解、微积分、积分、基本统计、函数/公式定义、绘图等。

    它被称为ParserNG 并且它是开源的。

    评估一个表达式很简单:

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

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

     MathExpression expr = new MathExpression("r=3;P=2*pi*r;"); 
    System.out.println("result: " + expr.getValue("P"));
    

    或者使用函数:

    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
    

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

    MathExpression expr = new MathExpression("f(x)=x^3*ln(x); diff(f,3,1)"); 
    System.out.println("result: " + expr.solve());
    
     result: 38.66253179403897
    

    在 x=3 时区分 x^3 * ln(x) 一次。 你现在可以区分的次数是 1。

    或数值积分:

    MathExpression expr = new MathExpression("f(x)=2*x; intg(f,1,3)"); 
    System.out.println("result: " + expr.solve());
    
    result: 7.999999999998261... approx: 8
    

    此解析器速度相当快,并且具有许多其他功能。

    免责声明:ParserNG 由我创作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-30
      • 2012-07-01
      • 2016-09-13
      相关资源
      最近更新 更多