(later edit)
Just finished this assignment. I was limited to using System and using System.collections.Generic. Nothing else. I ended up using a List<> from the from the collections.Generic. and the principles of Polish Notation. After every "Encounter" of a operation sign (+-/*) I used the index - 1 and - 2 to get the previous 2 numbers and make the operation. Then I used .Insert to insert the result at the current index, afterwards I used .Remove to substract from the list the numbers and the operator which I just used and after I continued with the recursive function on the new list obtained starting with the index from 0 again. The polish notation articles posted in the comments helped me the most to understand the logic behind this
*
I'm trying to figure out from the past several days a way to implement the following logic into a c# program. Using only System.
This is a small console calculator where the input is inserted on a single line in the console.
For example the following input + / * + 65 32 46 2 - 1 1.25 should be translated into a math operation looking like this => ((65 + 32) * 46) / 2 + (1 - 1.25)
Another example would be * + 3 2 - 9.5 6.5: this should be calculated in the following order 3 + 2 * (9.5 - 6.5).
Another example / + 5 3 2 equals with => (5 + 3) / 2
I have to make the function recursive.
I figured out how to make it if all the operations sings are in front of the digits in the input. (I just separate the operator list and inverse it and I get two separate lists: one containing the operation signs and the other containing the numbers). What I'm struggling is to figure out a way to do the operations if there is a math sign in between the numbers (like in the first an the second example).
I don't necessarily need a code for this, maybe an explanation or if somebody could point me to the right direction where I can read about some algorithm / math formula or something that could help me better understand how to implement this.
Thank you in advance.
The normal method of evaluating Polish Notation expressions doesn't require recursion, you use a stack (like Forth or RPN) and evaluate as you go.
An easy way to create a recursive version is to consider the expression language BNF then crafting a recursive descent parser from the grammer.
For example, a possible BNF would be:
expr = op arg arg
op = [+-*/] // cheating; use regex to describe terminal
arg = number | expr
number = [0-9]+ // using Regex to describe terminal
So now you would create methods for each element:
double expr() {
string opStr = op();
double arg1 = arg();
double arg2 = arg();
double ans;
switch (opStr) {
case "+":
ans = arg1+arg2;
break;
// case and so on
}
return ans;
}
static string operators = "+-*/";
string op() {
if (operators.Contains(peekChar()))
return nextCharAsStr();
else
throw new Exception("Missing operator");
}
double arg() {
double? num = number();
if (num.HasValue)
return num.Value;
else
return expr();
}
double? number() {
string ans = "";
while (Char.IsDigit(peekChar()))
ans += nextCharAsStr();
if (String.IsNullOrEmpty(ans))
return null;
else
return Double.Parse(ans);
}
NOTE: Whitespace and end of string is left as an exercise to the reader.
You could also use a tokenizer that extracts terminals from the string instead of working directly with characters in the parser terminal methods.
There are different kinds of recursion. The most common (code recursion) is probably what you're asking about, wherein a function (or set of functions) call each other until some sort of exit condition is reached.
For this, I'd go with more of a data recursive approach. This version only supports single-digit operands and binary operators.
(Really bad pseudocode below).
stack<char> operators;
stack<char> operands;
for(var i=input.Length-1; i>=0; --i)
{
var c = input[i];
if (Char.IsDigit(c)) /// note that this only handles single-digit numbers.
operands.push(c);
else
operators.push(c);
if (operators.count >= 1 && operands.count >= 2)
{
var operator = operators.pop();
/// handle binary operators
left = operands.pop();
right = operands.pop();
switch(operator) {
case '+' : result = left + right; break;
case '-' : result = left - right; break;
case '*' : result = left * right; break;
case '/' : result = left / right; break;
}
operands.push(result);
}
}
var result = operands.pop();
When that completes, your operands stack should have only one item which is the result of the expression. and operators should be empty.
If you have leftover operators, then there weren't enough values in the input. If you have more than one value in operands, there weren't enough operators in the input. If you have zero operands (ie, no result), then there weren't any in the input to start with.
For a real implementation, you'd want to parse the string to get multi-digit operands, handle unary operators, ignore whitespace, etc.
Edit: reversed the loop direction.