Reputation: 6939
Hi everyone I am new in the Android world and I am trying to build I guess a medium difficulty calculator app. I came up with this kind of a structure, but didn't implement anything yet cause I'm a little bit in doubt if this could be the right way. So here I go:
I have an Operand interface with kind of a method called "getValue()" that should return a double type, and some other objects that implement that interface, thus implement that "getValue()" method:
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;
}
...
}
In this way even with a sub-expression inside an expression like "3 + (4 * 3 - 2 * (4 - 1) / 2 + 5))" will be evaluated like an Operand thanks to the interface, in particular in this case:
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 class that implements Operand that will be a simple Wrapper class for a double value, and that will return that double in the getValue() method that it implements.
Function class with an enum type that says if it is a SIN, COS, TAN, ARCSIN, ARCCOS, ARCTAN, LOG or LN function, always with the getValue() method that returns the double result of the computation of the function;
Utility, this class could be misunderstood: it is a class for those operations like the exponentiation, square root, the percentage of a number or its factorial. The idea here is to use an enum type again to distinguish the type of operation. I know that an exponentiation is an operation itself but it looks better to me to keep it a bit away from the previously explained Operation class cause the structure and computation is different (I would like to treat the Exponentiation like an Operand type, not an Operation, for me an Operation involves only two Operands and an Operator as I said before).
Then I know that, given an Expression like:
3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2
The data structure would be:
Operand Operand
| |
3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2
| ¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Operand Operand
4 operands, thus 3 operations, but I need to establish the priority, so I thought that I should iterate over the operationList (the private field in the Expression object) to get such a priority, cause my data structure would be like (based on this expression, pseudo code):
List:
- 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));
Iterating over this List I can find that the Operation number 2 (Item n° 2) must be performed before the operation number 1. But I think this way is not so good cause you see I need to tidy up all the ArrayList every time I get the result from an Operation cause when the Operation N° 2 is performed and gets the double result, I need to create a Number() object for that result to treat it again like an Operand and reorganize the ArrayList in a way that the Operation number one has not Number(4) as a second operand anymore, but has the new result from the Operation 2 getResult() wrapped in a Number object. Also the Operation at position 3 has not an Expression as first operand anymore, but has the result from the previous operation as Operand.
It seems to me that kind of a structure is a little expensive to handle and I am asking if someone faced the same problem and came up with a better solution, or this solution may be fine. Another way is to store the complete Expression as a String and parse it with a RegExp to determine all the operation in sequence. Is it a better solution cause I would like to let the user change an Operand on the fly if while he is typing the expression, i.e. if he wrote the previous expression:
3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2
He could change the √4 to a ln(6) if he wants to do that before clicking the "Equals" button to perform the operation. So I guess using the previously ArrayList it would be difficult to manage such change, cause I would need to keep the position of each Operand of my Expression...
How does e.g. Google does this in his calculator app e.g. if you look at -> 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
I know it's Javascript but I guess the logic is the same for every language.
What do you think may be a possible solution? Thank you for the attention!
EDIT: something I did not understand:
/**
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();
}
This method calls the .compileSimple of the Compiler compile object:
Function compileSimple(Symbols symbols, String expression) throws SyntaxException {
rpn.setConsumer(simpleCodeGen.setSymbols(symbols));
lexer.scan(expression, rpn);
return simpleCodeGen.getFun();
}
Which returns a Function object and then calls the eval() method on that. Looking at the Function.eval() method I saw this:
/**
Evaluates an arity-0 function (a function with no arguments).
@return the value of the function
*/
public double eval() {
throw new ArityException(0);
}
The method eval must return a double type and the implementation throws an ArityException which has this implementation:
public class ArityException extends RuntimeException {
public ArityException(String mes) {
super(mes);
}
public ArityException(int nArgs) {
this("Didn't expect " + nArgs + " arguments");
}
}
How does it evaluates the String and returns a double if it throws an ArityException?
Upvotes: 3
Views: 1624
Reputation: 5916
You might want to take a look a the source code of the official Android calculator app which comes packaged with the platform.
I think the Logic.java will be the class that you are looking for. It has the code for the formatting, checking for operators, valuation etc: Android Calculator
EDIT
The Android calculator uses the Arity Arithmetic Engine, which is an open source library for evaluating arithmetic expressions represented as strings. I was not able to find an alive link for the project, it has been removed from code.google.com. But you can refer to the following links for more info:
Upvotes: 2