在Java中评估数学表达式的方法

Eth*_*roy 49 java math formula

在我的一个项目中,我想添加一个功能,例如用户可以在公式中提供

sin (x + pi)/2 + 1
Run Code Online (Sandbox Code Playgroud)

我在我的Java应用程序中使用它

/**
 * The formula provided by the user
 */
private String formula; // = "sin (x + pi)/2 + 1"

/*
 * Evaluates the formula and computes the result by using the
 * given value for x
 */
public double calc(double x) {
    Formula f = new Formula(formula);
    f.setVar("x", x);
    return f.calc();
    // or something similar
}
Run Code Online (Sandbox Code Playgroud)

我如何评估数学表达式?

fas*_*seg 23

还有exp4j,一个基于表达式的表达式评估器Dijkstra's 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();
Run Code Online (Sandbox Code Playgroud)

使用较新的API版本时0.4.8:

Expression calc = new ExpressionBuilder("3 * sin(y) - 2 / (x - 2)")
    .variable("x", x)
    .variable("y", y)
    .build();
double result1 = calc.evaluate();
Run Code Online (Sandbox Code Playgroud)

还有一个在exp4j中使用自定义函数的工具.

  • 对exp4j 0.3.5以后增加了对科学记数法的支持 (2认同)

Sni*_*las 9

这取决于你想要评估的表达式有多复杂,但对于简单的表达式,java有一个非常好的javascript引擎:

import javax.script.*;
public class EvalScript {
public static void main(String[] args) throws Exception {
    // create a script engine manager
    ScriptEngineManager factory = new ScriptEngineManager();
    // create a JavaScript engine
    ScriptEngine engine = factory.getEngineByName("JavaScript");
    // evaluate JavaScript code from String
    Object obj = engine.eval("1+2");
    System.out.println( obj );
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我绝对不会喜欢这种技术。它很容易受到注入式攻击的攻击,就像几乎所有基于通用评估的技术一样。不好的做法。 (2认同)

Udo*_*ski 8

为了扩展列表,我也完成了一个:

https://github.com/uklimaschewski/EvalEx

EvalEx是Java的一个方便的表达式计算器,它允许评估简单的数学和布尔表达式.

主要特点:

  • 使用BigDecimal进行计算和结果
  • 单一类实现,非常紧凑
  • 没有外部库的依赖
  • 可以设置精度和舍入模式
  • 支持变量
  • 标准布尔和数学运算符
  • 标准基本数学和布尔函数
  • 可以在运行时添加自定义函数和运算符

例子:

BigDecimal result = null;

Expression expression = new Expression("1+1/3");
result = expression.eval():
expression.setPrecision(2);
result = expression.eval():

result = new Expression("(3.4 + -4.1)/2").eval();

result = new Expression("SQRT(a^2 + b^2").with("a","2.4").and("b","9.253").eval();

BigDecimal a = new BigDecimal("2.4");
BigDecimal b = new BigDecimal("9.235");
result = new Expression("SQRT(a^2 + b^2").with("a",a).and("b",b).eval();

result = new Expression("2.4/PI").setPrecision(128).setRoundingMode(RoundingMode.UP).eval();

result = new Expression("random() > 0.5").eval();

result = new Expression("not(x<7 || sqrt(max(x,9)) <= 3))").with("x","22.9").eval();
Run Code Online (Sandbox Code Playgroud)