CONTEXT: I am making an infix calculator in Java, and am now on the point where I'm implementing unary plus and minus. An operator is unary if it comes in where a value is expected. This would be any of the following: at the start, after an operator or after an opening parenthesis.
Relevant information: (Assume what I say in this section works as intended...because it does.)
I read in a line (which is checked to be an equation beforehand), and store it as an array of strings, delimited by spaces, called readin[].
When I encounter an "operator" (plus, minus, open paren, etc) in this equation, I push it to a stack called ops. Exceptions are for closing parenthesis, which forces a calculation to the last open parenthesis, and for these unary operators.
When I encounter a "value" (ie. a known, initialized variable, or a number), I push it to the values stack. All variables must start with a letter.
I cycle through each element in readin[], keeping track with the value i, thus i is the current element, and i-1 is the previous element in the array from what we are currently looking at.
With few exceptions, all math is done after interpreting the full equation.
The Shortcut (Code):
if(readIn[i].charAt(0) == '-'){
if(ops.empty() && values.empty()){
//is unary, set negative
}
else if( readIn[i-1].charAt(0) == ops.peek() ){
//is unary, set negative
}
//it isn't unary, continue onwards
}
What it's Doing (Plain English): It checks if we've encountered a minus sign, and if we did, it checks the following. If either of the following are true, then this minus sign is deemed "unary".
If the operator stack is empty, while the the values stack is also empty. If the previous element in the equation is on the operator stack, and thus is an operator.
Why's it doing that? Because if we didn't encounter a minus sign, then we definitely didn't encounter a unary minus sign.
If we don't have anything on the stacks, then we have either catastrophically failed somewhere, or we're at the beginning of the equation. As mentioned, an operator at the start is indicative of a unary operator. (However, I don't think the operator stack is too useful in determining this, so it may be a superfluous check.)
If the last element in the string array is an operator (including open parenthesis), then we are encountering this minus sign after an operator, which is also indicative of a unary operator.
By the way, "set negative" just flips a boolean value which modifies the next incoming value, so 5 consecutive minus signs ought to "add the negative" of the next value coming in, the same way 1 minus sign does so.
The Question: Are there any inherent problems that would arise from this code, based on the information given? Maybe ones that wouldn't result from standard equations.
Yes. There is at least 1 problem with this solution. It's when you encounter an empty ops stack, but not an empty values stack, because it ends up checking both cases, if there is a value on the stack. And thus, it tries to peek in to an empty stack of operators. This obviously throws an error.
However, if you were to add a check for if the ops stack is empty, before trying to peek in and compare it, then that should work out.
This should also still fulfil the requirements in an infix calculator, as you won't ever have an empty ops stack if you are actually encountering the minus sign right after an operator (since it can't be used if you're encountering the minus sign, and not a number).....at least, not in any case that I can think of.
Related
The ternary operator normally just is a subject to philosophical discussions:
whether
a=b>5?1:0;
is more readable, faster, cooler to
if(b>5) { a=1; } else {a=0;}
(take or leave the curly braces) I normally don't care. I like my ternary operator. But we had a discussion concerning this piece of code:
BigObject myBigObject=null;
...
do {
myBigObject=
myBigObject==null?
createBigObject():
myBigObject;
...
} while(manyIteration);
Colleague claimed that this construct will create the myBigObject will be copied every loop (except the first) which will waste precious time and memory
and that he found the case where the ternary operator is useless. the only way is:
do {
if(myBigObject==null)
myBigObject=createBigObject();
...
} while(manyIteration);
I argued that the clever compiler will see that the object is assigned to itself and will optimize it out.
But who is right?
The definite answer lies in section 15.25 of the JLS (emphasis mine):
The resulting boolean value is then used to choose either the second or the third operand expression:
- If the value of the first operand is true, then the second operand expression is chosen.
- If the value of the first operand is false, then the third operand expression is chosen.
The chosen operand expression is then evaluated and the resulting value is converted to the type of the conditional expression as determined by the rules stated below.
This conversion may include boxing or unboxing conversion (§5.1.7, §5.1.8).
The operand expression not chosen is not evaluated for that particular evaluation of the conditional expression.
This means both expressions are not always evaluated: only the one that needs to be is. So actually, none of you are right.
You're wrong because it is not the compiler being clever: it is specified by the language itself;
Your collegue is wrong because the expression won't be evaluated if need not be.
In the code
myBigObject = myBigObject == null ? createBigObject() : myBigObject;
^-----------------^ ^---------------^
this is true the 1st time, hence that ^ is evaluated
myBigObject = myBigObject == null ? createBigObject() : myBigObject;
^-----------------^
this is false the 2nd time, hence that ^ is NOT evaluated, that ^ is
Notice that what is executed is just assigning myBigObject to itself, which does not create a new object.
Colleague claimed that this construct will create the myBigObject will be copied every loop (except the first) which will waste precious time and memory and that he found the case where the ternary operator is useless.
You should note that myBigObject is a reference to an object. This means it is 4 bytes on most JVMs and a redundant copy isn't going to make a big difference.
I argued that the clever compiler will see that the object is assigned to itself and will optimize it out.
Possibly, though I don't see it will make much difference either way.
While a compiler can remove redundant code, it is harder for a human to remove redundant code. In general we code with a purpose. When code has no purpose it is much harder to come to that conclusion. I suggest you avoid confusing anyone who has to read/maintain the code in the future.
As ever, when discussing performance, you should first consider clarity. How surprising in this construct and how easy is it to maintain.
The cost of a redundant assignment (which may or may not be optimised away) is nothing compared with the cost of even an easy to fix bug (never mind a hard to fix one)
You should focus on what is clearer (which is subjective) and not worry about micro-tuning the code unless you have a profiler which indicates this line is a performance issue.
For me, this is clearer, but even if it were slower, I would still argue it is clearer and easier to understand what it is doing.
if (myBigObject == null)
myBigObject = createBigObject();
The fact you have already had to have a discussion but what that code is really doing, means you have spent more time than you can possibly recover.
In short, developer efficiency is usally more important than computer efficiency.
Your colleague is wrong. After the first iteration myBigObject is no longer null and hence won't be created. Sample code proves this...
public static void main(String[] args) {
Object myBigObject=null;
int i=0;
do {
System.out.println("Iteration " + i);
myBigObject=
myBigObject==null?
createBigObject():
myBigObject;
} while(i++ < 10);
}
private static Object createBigObject() {
System.out.println("Creating bigObject");
return new Object();
}
The output of which is
Iteration 0
Creating bigObject
Iteration 1
Iteration 2
Iteration 3
Iteration 4
Iteration 5
Iteration 6
Iteration 7
Iteration 8
Iteration 9
Iteration 10
See how the create statement is only printed once
Why does your colleague think that?
Only exactly one branch of a ternary conditional is ever evaluated. Imagine if it were not the case? So much code of the form obj == null ? null : obj.someproperty() would break!
So your object will only be created once.
I came across multiple links to the solution of the problem - "How to check if a string is interleaving of two other strings"
Two solutions looked particularly interesting to me which work but I have doubts in both of them.
FIRST I did not get the hashing part in this where author is saying "A pure recursive solution will cause time limit exceed. We can optimize it by caching the false visited solutions in the visited set. That will short circuit many repeated search path"
SECOND I did not the the "else condition" on line 18 in recursive. Won't one of the conditions (line 14th and line 16th) will always be true as they are inside else of line 11th if condition which is if(s2.charAt(0) != s3.charAt(0) && s1.charAt(0) != s3.charAt(0)) {
First
This is actually space-time tradeoff (the computation time can be reduced at the cost of increased memory use). Why does the author say pure recursive solution slow (in fact it's exponential time complexity)? It comes from repeated recursion and because of that, it computes the same values again and again.
So what can you do? You can store the value you already computed. Next time you want this value again, just look up in a table. This is called caching, when the values are cached, you can treat every recursive call inside the function as it would run in O(1) time complexity. The core idea is don't calculate the same things twice.
Second
In the case s2.charAt(0) == s3.charAt(0) && s1.charAt(0) == s3.charAt(0).
Given the expression:
1/2/3/4*5
It reaches the end of the expression and attempts to multiply out the 4 and 5 first WHICH IS WRONG because it begins to pop off the stack. I'm not necessarily doing RPN but just evaluating on the spot. How can I prevent this?
// Expression was completely read - so we should try and make sense of
// this now
while (operatorStack.size() != 0) {
ApplyOperation(operatorStack, operandStack);
}
At this point, I begin to pop off operators and operations. Since multiplication and division have the same presence, they start with multiplication.
A trace:
1/2/3/4*5
Applying * to 5 and 4
Result: 20
Applying / to 20 and 3
Result: 3/20
Applying / to 3/20 and 2
Result: 40/3
Applying / to 40/3 and 1
Result: 3/40
There is a point in the shunting yard algorithm at which you compare the precedence of the operator at the top of the stack with the precedence of the operator in the input stream, and decide whether to pop the stack (evaluate the stacked operator, in your case), or push the new operator.
It makes a big difference if the comparison is < or <=. One of those will produce left-associativity, and the other will produce right-associativity. Since you're getting right-associativity and you want left-associativity, I'm guessing (without seeing your code) that
you're using the wrong comparison operator.
By the way, your professor is quite correct. There is no need to explicitly produce RPN, and the evaluation algorithm will indeed pop the entire stack when it reaches the end of input. (The RPN algorithm would also do that; the evaluation algorithm is simply a shortcut.)
What operatorStack? The RPN resulting from the shunting-yard algorithm is a list, not a stack. It is processed from left to right, not FIFO,
Can anybody explain how this function works?
public int TestAdd(int a,int b) {
if(a <1)return b;
return(TestAdd((a&b)<<1,a^b));
}
Adding two matching set binary digits is equivalent to setting the next bit up: 1+1=2, and so on. So the function does that for all matching bits, then carries the unmatched ones over to another round. When no unmatched ones remain, it's done.
Since you can obviously test to see that it does indeed add two numbers, I assume you aren't understanding what those symbols are doing. Java's operators are described here:
http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
And you can easily look up the definitions of "logical AND" and "bitwise exclusive OR" and how they apply to ints.
Here we using the concept of recursion, this function call itself as values-
1 bit left shift of binary(Due to carry while adding) addition of numbers and xor of numbers until the a become <1.
Thus it returns the addition of numbers.
You can debug the function by taking some values for better understanding.
The code below is a chunk from actual code of Calculator.What it does is that user presses a number on the calculator then as he presses "+" the number on the text field gets stored and then he presses the next number and it gets stored when he presses "=".Then in "=" if condition the addition function is performed.Now i want both addition and subtraction running at one time that is after doing addition user wants to do subtraction then HOW will i do it????
if(a.getActionCommand().equals("+"))
{
q=tf.getText();
x=Integer.parseInt(q);
}
if(a.getActionCommand().equals("-"))
{
b=tf.getText();
t=Integer.parseInt(b);
}
if(a.getActionCommand().equals("="))
{
p=tf.getText();
y=Integer.parseInt(p);
z=x+y;
//z=t-y;
w=Integer.toString(z);
tf.setText(w);
}
Calculators generally perform an = operation whenever they process an action like + or -. Try it, open the calc app on your computer now and try 3 + 5 - 1. When you press the -, the display will show 8. You can do the same with yours and handle as many + and - operations in a row as you would like. There would be some refactoring to do to the code you've posted, and one thing you could do there would be to methodize the process that you use for the = operation. You could then call that performEquals at the beginning of each + or - block.
A stack based algorithm as jcomeau_ictx suggests is a very viable solution to your problem.
Create two stacks: one that holds operators (+, -, *, /) and one that holds operands (the set of numbers 0-9).
Support the user presses: 3 + 4 - 5
Steps:
1.) Push '3' into the operand stack
2.) Push '+' into the operator stack
3.) Push '4' into the operand stack.
Since there are at least 2 operands, calculate 3 + 4 (which is 7).
4.) Pop 3 and 4. Add these two and pop them to the operand stack
5.) Pop + from the operator stack and push -.
6.) Push 5 onto the stack. Subtract these two and place result in operand stack.
General Algorithm:
Push operand (or operator) into the stack
if (operands > 2 && operator > 0)
pop both operands and one operator;
calculate result;
place result in operand stack;
reset operator stack;
How about: accept a negative number as input, then add? Or am I missing the point?
If not, then using RPN would work, no need for "=" at all. Enter two numbers, then the "+" or "-" will take the two operands off the stack, apply the operator, and push the result back onto the stack, displaying it.
Third way: instead of your code for "-", use:
if(a.getActionCommand().equals("-"))
{
b=tf.getText();
x=-(Integer.parseInt(b));
}
Not sure if I've taken everything into account on that last suggestion, but it's a start.
I assume that you have 4 operations ( +, - , ×, ÷ ), and that you're implementing a basic desktop calculator that doesn't implement order of operations. In this case, jcomeau_ictx's x=-(Integer.parseInt(b)) won't work because it can only deal with subtraction, not multiplication and division, and these stack-based solutions are overkill.
What you is 3 variables: firstNumber, operation and secondNumber. operation starts out empty (or using some value that indicates "empty"). When the user hits =, what you need to do is take the number from the display and put it into secondNumber. Then look at all 3 variables and perform the indicated in the operation variable.
When the user hits +, - , ×, or ÷, first you perform the = operation (put the user's input into secondNumber and perform the operation indicated by the operation variable). Put the result into firstNumber (and display it on the screen if you wish). Then store the operation that the user hit (+, - , ×, or ÷) in the operation variable, so that you can perform that operation the next time the user hits +, - , ×, ÷, or =.