2016-02-25 120 views
1

我有以下阶乘运营商宣称:EXP4J:不能得到很好的阶乘运营工作

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没有问题。

这对我正在进行的项目具有破坏性。有人建议将操作符转换为函数,但这会花费太多时间。我试着改变所有的构造参数,但没有一个改变了这个问题。

+1

打开此问题:https://github.com/fasseg/exp4j/issues/62 – fasseg

回答

1

我发现了一个解决方法,它将使阶乘按预期工作。诀窍是添加第二个变量,并使阶乘伪操作符,因此:

而不是: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时。

0

这当然与连续有两个操作员有关。或者,它也可能与EXP4J是表达式分析器的糟糕实现有关。

无论如何,你看看它,没有简单的解决方案使用EXP4J。它根本无法处理后缀运算符的任务。 (如果您准备使用!5来表示“5阶乘”,那么不会有问题;只要确保您给它与其他一元前缀运算符相同的优先级即可。但是,您不希望使用函数建议您不想更改!的语法。)

大提示是,Operator构造函数没有任何方法来指定运算符是前缀还是后缀。 (!后缀运营商,因为它遵循其操作数,不像,说,用的是前缀一元-。)

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

针对一元运算符+-的特例黑客与黑客进行严重的交互,而黑客并不试图检查一元运算符是前缀还是后缀。在5!+5中,+紧跟在运算符后面,EXP4J将其解释为指示+是前缀一元运算符+。因此,它解析的几乎就像是(5!)(+5),只是它不会插入如果您实际编写(5!)(+5)就会插入的隐式乘法。

所以你会得到一个例外,因为你不能在它们之间没有操作符的情况下有两个值。

实际上修复这将需要相当多的重写。使用不同的表达式求值器或者使用标准的解析器生成器将自己扔到一起可能会更好。

+0

经过大量的搞乱之后,我发现一个解决方法比用另一个表达式解析器重写我的所有程序容易一些。看到我的答案。 –