EXP4J:无法让一个好的阶乘算子工作

时间:2016-02-25 16:18:49

标签: java android parsing

我声明了以下阶乘运算符:

Operator factorial = new Operator("!", 1, true, Operator.PRECEDENCE_POWER + 1) {
  @Override public double apply(double... args) {
    final long arg = (long) args[0];
    if ((double) arg != args[0]) {
      throw new IllegalArgumentException("Operand for factorial has to be an integer");
    }
    if (arg < 0) {
      throw new IllegalArgumentException("The operand of the factorial can not " +
      "be " +
      "less than zero");
    }
    double result = 1;
    for (int i = 1; i <= arg; i++) {
      result *= i;
    }
    return result;
  }
};

因此,当你有5!之类的简单表达式时,它可以正常工作,但是当你试图模拟正常的计算器行为时,事情就会开始破坏。以下示例抛出IllegalArgumentException()

5!+5

为什么呢?我想它与2个相邻的运算符或其他东西有关,因为使用(5!)+5没有问题。

这对我正在进行的项目来说是毁灭性的。有人建议将运算符转换为函数,但这需要花费太多时间。我已经尝试更改所有构造函数参数,但没有一个更改问题。

2 个答案:

答案 0 :(得分:1)

我找到了一种解决方法,可以使因子按预期运行。诀窍是添加第二个变量并使factorial成为伪的unrary运算符,所以:

而不是:5!+5我使用了:5!(1)+5。这在我的程序中不需要重构,因为唯一的改变是操作员的输入方式。

这样,解析器运行得非常好。您还需要将实际的Operator声明更改为:

Operator factorial = new Operator("!", 2, true, Operator.PRECEDENCE_POWER + 1) {
  @Override public double apply(double... args) {
    final long arg = (long) args[0];
    if ((double) arg != args[0]) {
      throw new IllegalArgumentException("Operand for factorial has to be an integer");
    }
    if (arg < 0) {
      throw new IllegalArgumentException("The operand of the factorial can not " +
      "be " +
      "less than zero");
    }
    double result = 1;
    for (int i = 1; i <= arg; i++) {
      result *= i;
    }
    return result;
  }
};

我想在使用EXP4J时应该完全避免使用一元运算符。

答案 1 :(得分:0)

这肯定与连续两个运营商有关。

或者,它可能与EXP4J是表达式解析器的不良实现有关。

无论如何你看一下,使用EXP4J没有简单的解决方案。这根本不是处理后缀运算符的任务。 (如果你准备使用!5表示“5阶乘”,那就不会有问题;只要确保你给它的优先级与其他一元前缀运算符相同。但事实上你不要我想使用函数表明你不想改变!的语法。)

大提示是Operator构造函数没有任何方法来指定运算符是前缀还是后缀。 (!是一个后缀运算符,因为它跟在其操作数之后,不像是带有前缀的一元-。)

如果表达式解析器不知道,它肯定无法验证输入,并且有充分的理由相信它也无法准确地解析它。 [注1]另一个提示是自定义运算符需要声明为采用1或2个操作数,这意味着自定义运算符不能像-那样具有前缀和中缀语法。

一元+-运算符的特殊情况hack与hack交互不良,黑客不会尝试检查一元运算符是前缀还是后缀。在5!+5中,+紧跟在运算符之后,EXP4J将其解释为表示+是前缀一元+。所以它解析它几乎就像它是(5!)(+5)一样,除了它没有插入它实际写入(5!)(+5)时会插入的隐式乘法。

所以你得到了例外,因为你不能在它们之间没有运算符的情况下并排获得两个值。

实际上修复它需要相当多的重写。最好不要使用不同的表达式求值程序,或者将自己的表达式求解器与标准的解析器生成器一起使用。