我有一个“Operand”接口,其中包含一个名为“getValue()”的方法,该方法应返回double类型,以及一些其他实现该接口的对象,从而实现了“getValue()”方法:
Expression, I thought about making this an object with a private member field which would store all the Operations, so this Expression Object would have something like this:
public class Expression implements Operand { private List<Operation> operationList; ... }
The operationList would be an ArrayList where Operation is another object that would involve two operands (thus two Operand interfaces as type) bound together with an Operator object which has an enum type that says if the operation which involves this two operands is a SUM, DIV, MUL or a SUB. Something like:
public class Operation { private Operand operand1; private Operand operand2; private Operator operator; public Operation(Operand operand1, Operator operator, Operand operand2) { this.operand1 = operand1; this.operand2 = operand2; this.operator = operator; } public double getResult() { if (operator.getType() == Operator.Type.SUM) { return operand1.getValue() + operand2.getValue(); } else if (operator.getType() == Operator.Type.SUB) { return operand1.getValue() - operand2.getValue(); } else if (operator.getType() == Operator.Type.MUL) { return operand1.getValue() * operand2.getValue(); } else if (operator.getType() == Operator.Type.DIV) { return operand1.getValue() / operand2.getValue(); } return 0; } ... }
operator All this is another Expression object (a sub-expression that is treated
| | like an Operand
| ________|____________ cause it implements the Operand
3 + (4 * 3 - 2 * (4 - 1)) interface).
|
Operand operand1
Number类实现了Operand接口,它将是一个简单的包装类,包含一个double值,并在它实现的getValue()方法中返回该double值。
Function类有一个枚举类型,指示它是SIN、COS、TAN、ARCSIN、ARCCOS、ARCTAN、LOG还是LN函数,始终使用getValue()方法返回函数计算的double结果;
Utility类可能会被误解:它是一个用于指数、平方根、数字百分比或其阶乘等运算的类。这里的想法是再次使用枚举类型来区分操作类型。我知道指数是一种独立的运算,但我认为将其与先前解释的Operation类稍微分开会更好,因为结构和计算方式不同(我希望像操作数类型一样将指数作为操作数类型而不是操作符类型进行处理,对我来说,操作只涉及两个操作数和一个操作符)。
然后我知道,如果给定一个表达式:
3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2
数据结构将是:
Operand Operand
| |
3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2
| ¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Operand Operand
4个操作数,因此有3个操作,但我需要确定优先级,所以我认为应该迭代操作列表(Expression对象中的私有字段)以获得这样的优先级,因为我的数据结构将会是这样的(基于这个表达式的伪代码):
列表:
- Item n° 1 -> Operation(Number(3), Operator(Operator.Type.SUM), Number(4));
- Item n° 2 -> Operation(Number(4), Operator(Operator.Type.MUL), Expression("(5 + 2) - √4 + sin(4) + 3²"));
- Item n° 3 -> Operation(Expression("(5 + 2) - √4 + sin(4) + 3²"), Operator(Operator.Type.DIV), Number(2));
遍历这个列表后,我发现操作编号2(第2项)必须在操作编号1之前执行。但我认为这种方式不太好,因为每次从操作获取结果时,我都需要整理整个ArrayList。当执行操作N° 2并获得双倍结果时,我需要为该结果创建一个Number()对象,以再次将其视为操作数,并重新组织ArrayList,使操作1的第二个操作数不再是Number(4),而是操作2的getResult()中包装的新结果。另外,位置3的操作不再具有表达式作为第一个操作数,而是具有先前操作的结果作为操作数。
对我来说,这种结构有点难以处理,我想知道是否有人遇到过同样的问题并提出了更好的解决方案,或者这个解决方案可以接受。另一种方法是将完整的表达式存储为字符串,并使用RegExp解析它以确定所有操作的顺序。如果让用户随时更改操作数,例如在输入表达式时,这是更好的解决方案。
3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2
他可以在点击“等于”按钮执行操作之前将√4更改为ln(6)。因此,我猜使用先前的ArrayList来管理这种更改可能会很困难,因为我需要保持表达式中每个操作数的位置...
如何在计算器应用程序中实现这种功能,例如谷歌的计算器应用程序如何做到这一点?例如,如果您查看 ->https://www.google.it/search?q=2%2B2&oq=2%2B2&aqs=chrome.0.69i59j0l2j69i65l2j0.1141j0j7&sourceid=chrome&es_sm=94&ie=UTF-8#q=+3+%2B+4+*+((5+%2B+2)+-+sin(4)+%2B+3)+%2F+2。我知道这是Javascript,但我想逻辑对于每种语言都是相同的。
你认为可能的解决方案是什么?感谢关注!
编辑:有些我没有理解的东西:
/**
Evaluates a simple expression (such as "1+1") and returns its value.
@throws SyntaxException in these cases:
<ul>
<li> the expression is not well-formed
<li> the expression is a definition (such as "a=1+1")
<li> the expression is an implicit function (such as "x+1")
</ul>
*/
public synchronized double eval(String expression) throws SyntaxException {
return compiler.compileSimple(this, expression).eval();
}
这个方法调用编译器编译对象的.compileSimple方法:
Function compileSimple(Symbols symbols, String expression) throws SyntaxException {
rpn.setConsumer(simpleCodeGen.setSymbols(symbols));
lexer.scan(expression, rpn);
return simpleCodeGen.getFun();
}
这句话的意思是:返回一个函数对象,然后调用eval()方法。查看Function.eval()方法,可以看到以下内容:
/**
Evaluates an arity-0 function (a function with no arguments).
@return the value of the function
*/
public double eval() {
throw new ArityException(0);
}
方法eval必须返回一个double类型,实现会抛出一个ArityException异常,其实现如下:
public class ArityException extends RuntimeException {
public ArityException(String mes) {
super(mes);
}
public ArityException(int nArgs) {
this("Didn't expect " + nArgs + " arguments");
}
}
它如何评估字符串并在抛出ArityException时返回double?