Question
//This is a C# question and I am super stuck on this, please any help with explenation would be highly appreciated...THANK YOU!! using System; using
//This is a C# question and I am super stuck on this, please any help with explenation would be highly appreciated...THANK YOU!!
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions;
namespace Formulas { ///
/// Represents formulas written in standard infix notation using standard precedence /// rules. Provides a means to evaluate Formulas. Formulas can be composed of /// non-negative floating-point numbers, variables, left and right parentheses, and /// the four binary operator symbols +, -, *, and /. (The unary operators + and - /// are not allowed.) ///
public class Formula {
private bool lpPattern;
///
/// Creates a Formula from a string that consists of a standard infix expression composed /// from non-negative floating-point numbers (using C#-like syntax for double/int literals), /// variable symbols (a letter followed by zero or more letters and/or digits), left and right /// parentheses, and the four binary operator symbols +, -, *, and /. White space is /// permitted between tokens, but is not required. /// /// Examples of a valid parameter to this constructor are: /// "2.5e9 + x5 / 17" /// "(5 * 2) + 8" /// "x*y-2+35/9" /// /// Examples of invalid parameters are: /// "_" /// "-5.3" /// "2 5 + 3" /// /// If the formula is syntacticaly invalid, throws a FormulaFormatException with an /// explanatory Message. ///
public Formula(String formula) { //converts formula string to lowercase. formula = formula.ToLower(); //makes a stack to hold values and operators Stack valStack = new Stack(); Stack OpeStack = new Stack();
//The sequence "\\" matches "\" and "\(" matches "(". //tokenizing and splitting it //string[] token = Regex.Split(formula, "(\\()|(\\))|(-)|(\\+)|(\\*)|(/)");
// starts to store tokens according to GetTokens string[] token = GetTokens(formula).ToArray();
//first check to see if its empty or not valid if (token == null || token.Length == 0) { throw new FormulaFormatException("Not valid"); } if (IsOperator(token[0])) { if (!"(".Equals(token[0])) { //Starting w/ invalid token throw new FormulaFormatException("Only operator formula may start with is '('"); } } foreach (String token in tokens) { int value; if (" ".Equals(token) || "".Equals(token)) { continue; //ignore blank space } if (IsNumeric(token, out value)) { if (OpeStack.Count != 0 && ("*".Equals(OpeStack.Peek()) || "/".Equals(OpeStack.Peek()))) { //multiplication or division, time to evaluate and push result valStack.Push(PerformEvaluation(valStack.Pop(), value, OpeStack.Pop())); } else { //Just a value, no division or mult, just push to stack valStack.Push(value); } }
}
bool IsOperator(string tokenn) { return "*".Equals(tokenn) || "+".Equals(tokenn) || "-".Equals(tokenn) || "/".Equals(tokenn) || "(".Equals(tokenn) || ")".Equals(tokenn); }
bool IsNumeric(String tokenz, out int value) { value = 0; return int.TryParse(tokenz, out value); } else if (IsOperator(token)) { if (")".Equals(token)) { //closing parens, we need to evaluate inner
//Must contain at least two values on the stack or the closing paren is invalid if (valStack.Count < 2) { //throw new ArgumentException("Invalid formula, not enough values inside the parentheses."); }
//get the previous value int prevValue = valStack.Pop(); //now get the previous operator String prevOperator = OpeStack.Pop(); while (!"(".Equals(prevOperator)) {
//need to have a value on the stack to perform another operation if (valStack.Count == 0) { throw new ArgumentException("Invalid formula, expected a left value inside the parens, but none was found."); } int leftValue = valStack.Pop(); prevValue = PerformEvaluation(leftValue, prevValue, prevOperator);
//no previous operators and we didn't find the '(' formula is invalid if (OpeStack.Count == 0) { throw new ArgumentException("Invalid formula, expected a '(' with the ')' but wasn't found"); }
//get the next previous operator and do again. prevOperator = OpeStack.Pop(); } //found the opening parens, we are done, let's just push the value to the stack // we discard the parens here since we are done with evaluation. valueStack.Push(prevValue);
//one last check if * or / on stack we need to perform this now if (OpeStack.Count != 0 && ("*".Equals(OpeStack.Peek()) || "/".Equals(OpeStack.Peek()))) { if (valStack.Count < 2) { throw new ArgumentException("Invalid formula, unable to perform operation, as 2 values are not on the stack."); } int right = valStack.Pop(); int left = valStack.Pop(); valStack.Push(PerformEvaluation(left, right, OpeStack.Pop())); } } else if ("+".Equals(token) || "-".Equals(token)) { if (OpeStack.Count != 0 && ("+".Equals(OpeStack.Peek()) || "-".Equals(OpeStack.Peek()))) { //we got a + or - and already have a + or - on the stack. Evaluate now if (valStack.Count < 2) { throw new ArgumentException("Invalid formula, attempted to perform operation and not enough values on stack"); } int right = valStack.Pop(); int left = valStack.Pop(); valStack.Push(PerformEvaluation(left, right, OpeStack.Pop()));
} OpeStack.Push(token); } else { OpeStack.Push(token); } } else { //must be a variable - delegate should throw exception if not found int lookedUpValue = variableLookup(token.Trim()); if (OpeStack.Count != 0 && ("*".Equals(OpeStack.Peek()) || "/".Equals(OpeStack.Peek()))) { //multiplication or division, time to evaluate and push result if (valStack.Count == 0) { throw new ArgumentException("Invalid formula, expected another value for evaluation and none was found"); }
valStack.Push(PerformEvaluation(valStack.Pop(), lookedUpValue, OpeStack.Pop())); } else { //Just a value, no division or mult, just push to stack valStack.Push(lookedUpValue); } }
if (OpeStack.Count == 0) { if (valStack.Count != 1) { throw new ArgumentException("Invalid formula, invalid value count left at end of operation"); } return valStack.Pop(); } else { if (valStack.Count != 2 && OpeStack.Count != 1) { throw new ArgumentException("Invalid formula, too many operators and/or values left at end of Evaluation"); } int right = valStack.Pop(); int left = valStack.Pop(); //perform final evaluation return PerformEvaluation(left, right, OpeStack.Pop()); } } } } ///
/// Evaluates this Formula, using the Lookup delegate to determine the values of variables. (The /// delegate takes a variable name as a parameter and returns its value (if it has one) or throws /// an UndefinedVariableException (otherwise). Uses the standard precedence rules when doing the evaluation. /// /// If no undefined variables or divisions by zero are encountered when evaluating /// this Formula, its value is returned. Otherwise, throws a FormulaEvaluationException /// with an explanatory Message. /// public double Evaluate(Lookup lookup) { return 0; }
///
/// Given a formula, enumerates the tokens that compose it. Tokens are left paren, /// right paren, one of the four operator symbols, a string consisting of a letter followed by /// zero or more digits and/or letters, a double literal, and anything that doesn't /// match one of those patterns. There are no empty tokens, and no token contains white space. /// private static IEnumerable GetTokens(String formula) { // Patterns for individual tokens. // NOTE: These patterns are designed to be used to create a pattern to split a string into tokens. // For example, the opPattern will match any string that contains an operator symbol, such as // "abc+def". If you want to use one of these patterns to match an entire string (e.g., make it so // the opPattern will match "+" but not "abc+def", you need to add ^ to the beginning of the pattern // and $ to the end (e.g., opPattern would need to be @"^[\+\-*/]$".) String lpPattern = @"\("; String rpPattern = @"\)"; String opPattern = @"[\+\-*/]"; String varPattern = @"[a-zA-Z][0-9a-zA-Z]*";
// PLEASE NOTE: I have added white space to this regex to make it more readable. // When the regex is used, it is necessary to include a parameter that says // embedded white space should be ignored. See below for an example of this. String doublePattern = @"(?: \d+\.\d* | \d*\.\d+ | \d+ ) (?: e[\+-]?\d+)?"; String spacePattern = @"\s+";
// Overall pattern. It contains embedded white space that must be ignored when // it is used. See below for an example of this. This pattern is useful for // splitting a string into tokens. String splittingPattern = String.Format("({0}) | ({1}) | ({2}) | ({3}) | ({4}) | ({5})", lpPattern, rpPattern, opPattern, varPattern, doublePattern, spacePattern);
// Enumerate matching tokens that don't consist solely of white space. // PLEASE NOTE: Notice the second parameter to Split, which says to ignore embedded white space /// in the pattern. foreach (String s in Regex.Split(formula, splittingPattern, RegexOptions.IgnorePatternWhitespace)) { if (!Regex.IsMatch(s, @"^\s*$", RegexOptions.Singleline)) { yield return s; } } } }
///
/// A Lookup method is one that maps some strings to double values. Given a string, /// such a function can either return a double (meaning that the string maps to the /// double) or throw an UndefinedVariableException (meaning that the string is unmapped /// to a value. Exactly how a Lookup method decides which strings map to doubles and which /// don't is up to the implementation of the method. /// public delegate double Lookup(string var);
///
/// Used to report that a Lookup delegate is unable to determine the value /// of a variable. /// [Serializable] public class UndefinedVariableException : Exception { /// /// Constructs an UndefinedVariableException containing whose message is the /// undefined variable. /// /// public UndefinedVariableException(String variable) : base(variable) { } }
///
/// Used to report syntactic errors in the parameter to the Formula constructor. /// [Serializable] public class FormulaFormatException : Exception { /// /// Constructs a FormulaFormatException containing the explanatory message. /// public FormulaFormatException(String message) : base(message) { } }
///
/// Used to report errors that occur when evaluating a Formula. /// [Serializable] public class FormulaEvaluationException : Exception { /// /// Constructs a FormulaEvaluationException containing the explanatory message. /// public FormulaEvaluationException(String message) : base(message) { } }
sing System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Formulas;
namespace FormulaTestCases
{
///
/// These test cases are in no sense comprehensive! They are intended to show you how
/// client code can make use of the Formula class, and to show you how to create your
/// own (which we strongly recommend). To run them, pull down the Test menu and do
/// Run > All Tests.
///
[TestClass]
public class UnitTests
{
///
/// This tests that a syntactically incorrect parameter to Formula results
/// in a FormulaFormatException.
///
[TestMethod]
[ExpectedException(typeof(FormulaFormatException))]
public void Construct1()
{
Formula f = new Formula("_");
}
///
/// This is another syntax error
///
[TestMethod]
[ExpectedException(typeof(FormulaFormatException))]
public void Construct2()
{
Formula f = new Formula("2++3");
}
///
/// Another syntax error.
///
[TestMethod]
[ExpectedException(typeof(FormulaFormatException))]
public void Construct3()
{
Formula f = new Formula("2 3");
}
///
/// Makes sure that "2+3" evaluates to 5. Since the Formula
/// contains no variables, the delegate passed in as the
/// parameter doesn't matter. We are passing in one that
/// maps all variables to zero.
///
[TestMethod]
public void Evaluate1()
{
Formula f = new Formula("2+3");
Assert.AreEqual(f.Evaluate(v => 0), 5.0, 1e-6);
}
///
/// The Formula consists of a single variable (x5). The value of
/// the Formula depends on the value of x5, which is determined by
/// the delegate passed to Evaluate. Since this delegate maps all
/// variables to 22.5, the return value should be 22.5.
///
[TestMethod]
public void Evaluate2()
{
Formula f = new Formula("x5");
Assert.AreEqual(f.Evaluate(v => 22.5), 22.5, 1e-6);
}
///
/// Here, the delegate passed to Evaluate always throws a
/// UndefinedVariableException (meaning that no variables have
/// values). The test case checks that the result of
/// evaluating the Formula is a FormulaEvaluationException.
///
[TestMethod]
[ExpectedException(typeof(FormulaEvaluationException))]
public void Evaluate3()
{
Formula f = new Formula("x + y");
f.Evaluate(v => { throw new UndefinedVariableException(v); });
}
///
/// The delegate passed to Evaluate is defined below. We check
/// that evaluating the formula returns in 10.
///
[TestMethod]
public void Evaluate4()
{
Formula f = new Formula("x + y");
Assert.AreEqual(f.Evaluate(Lookup4), 10.0, 1e-6);
}
///
/// This uses one of each kind of token.
///
[TestMethod]
public void Evaluate5 ()
{
Formula f = new Formula("(x + y) * (z / x) * 1.0");
Assert.AreEqual(f.Evaluate(Lookup4), 20.0, 1e-6);
}
///
/// A Lookup method that maps x to 4.0, y to 6.0, and z to 8.0.
/// All other variables result in an UndefinedVariableException.
///
///
///
public double Lookup4(String v)
{
switch (v)
{
case "x": return 4.0;
case "y": return 6.0;
case "z": return 8.0;
default: throw new UndefinedVariableException(v);
}
}
}
}
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started