我声明了以下阶乘运算符:
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
没有问题。
这对我正在进行的项目来说是毁灭性的。有人建议将运算符转换为函数,但这需要花费太多时间。我已经尝试更改所有构造函数参数,但没有一个更改问题。
答案 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)
时会插入的隐式乘法。
所以你得到了例外,因为你不能在它们之间没有运算符的情况下并排获得两个值。
实际上修复它需要相当多的重写。最好不要使用不同的表达式求值程序,或者将自己的表达式求解器与标准的解析器生成器一起使用。