/// <summary> /// Mathematical calculator constructor with dependency injection /// </summary> /// <param name="parser">Parser of mathematical expression string</param> /// <param name="notationConverter">Converter for different mathematical notation</param> /// <param name="mathProcessor">Processor for performing mathematical operations</param> /// <param name="mathOperationsContainer">Mathematical operations</param> public MathCalculator(IParser parser, INotationConverter notationConverter, IMathProcessor mathProcessor, IMathOperationsContainer mathOperationsContainer) { _parser = parser; _notationConverter = notationConverter; _mathProcessor = mathProcessor; _mathOperationsContainer = mathOperationsContainer; }
/// <summary> /// Parse string to terms of mathematical expression /// </summary> /// <param name="expression">Input expression</param> /// <param name="mathOperationsContainer">Avaliable math operations</param> /// <returns>Parsed mathematical expression</returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="NullReferenceException"></exception> public IEnumerable <ExpressionUnit> Parse(string expression, IMathOperationsContainer mathOperationsContainer) { var result = new List <ExpressionUnit>(); var numberBuilder = new StringBuilder(); for (var i = 0; i < expression.Length; i++) { OperationType operationType = OperationType.Unary; var firstOperandExists = numberBuilder.Length != 0; var firstOperandInBracketsExists = result.Count() != 0 && result.Last().Type == ExpressionUnitType.RightBracket; if (firstOperandExists || firstOperandInBracketsExists) { operationType = OperationType.Binary; } if (TryParseExpressionUnit(expression[i].ToString(), operationType, mathOperationsContainer, out ExpressionUnit mathOperation)) { ParseNumber(result, numberBuilder); result.Add(mathOperation); continue; } numberBuilder.Append(expression[i]); } ParseNumber(result, numberBuilder); return(result); }
public MathCalculatorUnitTests() { _mathOperationsContainer = new MathOperationsContainer(); _mockParser = new Mock <IParser>(); _mockNotationConverter = new Mock <INotationConverter>(); _mockMathProcessor = new Mock <IMathProcessor>(); _calculator = new MathCalculator(_mockParser.Object, _mockNotationConverter.Object, _mockMathProcessor.Object, _mathOperationsContainer); }
private static MathOperation GetOperationByKeyword(ExpressionUnit item, IMathOperationsContainer mathOperationsContainer) { var operation = mathOperationsContainer.GetOperationOrDefault(item.Keyword); if (operation == null) { throw new ArgumentException("Invalid mathematical expression or unsupported operation."); } return(operation); }
/// <summary> /// Execute operations in a mathematical expression /// </summary> /// <param name="expression">Mathematical expression</param> /// <param name="mathOperationsContainer">Avaliable math operations</param> /// <returns>Execution result</returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="DivideByZeroException"></exception> /// <exception cref="NullReferenceException"></exception> public double Process(IEnumerable <ExpressionUnit> expression, IMathOperationsContainer mathOperationsContainer) { var stack = new Stack <double>(); foreach (var item in expression) { if (item.Type == ExpressionUnitType.Number) { stack.Push(double.Parse(item.Keyword, NumberStyles.Any, CultureInfo.InvariantCulture)); continue; } if (item.Type == ExpressionUnitType.Operation) { var operation = GetOperationByKeyword(item, mathOperationsContainer); operation.Operate(stack); } } return(stack.Peek()); }
/// <summary> /// Convert infix notation to reverse polish notation /// </summary> /// <param name="infixNotation">Infix notation</param> /// <param name="mathOperationsContainer">Avaliable math operations</param> /// <returns>Reverse polish notation</returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="NullReferenceException"></exception> public IEnumerable <ExpressionUnit> ConvertToReversePolishNotation(IEnumerable <ExpressionUnit> infixNotation, IMathOperationsContainer mathOperationsContainer) { var stack = new Stack <ExpressionUnit>(); var result = new List <ExpressionUnit>(); foreach (var item in infixNotation) { if (item.Type == ExpressionUnitType.Number) { result.Add(item); continue; } if (item.Type == ExpressionUnitType.LeftBracket) { stack.Push(item); continue; } if (item.Type == ExpressionUnitType.RightBracket) { while (stack.Count != 0 && !(stack.Peek().Type == ExpressionUnitType.LeftBracket)) { result.Add(stack.Pop()); } if (stack.Count == 0) { throw new ArgumentException("Invalid mathematical expression or non-infix notation."); } stack.Pop(); continue; } var operation = GetOperationByKeyword(item, mathOperationsContainer); if (operation.Type == OperationType.Unary) { stack.Push(item); continue; } while (stack.Count() != 0) { var peek = stack.Peek(); if (peek.Type != ExpressionUnitType.Operation) { break; } var peekOperation = GetOperationByKeyword(peek, mathOperationsContainer); if (peekOperation.Type != OperationType.Unary && peekOperation.Priority <= operation.Priority) { break; } result.Add(stack.Pop()); } stack.Push(item); } while (stack.Count() != 0) { var peek = stack.Peek(); if ((peek.Type == ExpressionUnitType.Operation) && !(peek.Type == ExpressionUnitType.LeftBracket)) { result.Add(stack.Pop()); } else { throw new ArgumentException("Invalid mathematical expression or non-infix notation."); } } return(result); }
private static bool TryParseExpressionUnit(string expressionItem, OperationType operationType, IMathOperationsContainer mathOperationsContainer, out ExpressionUnit expressionUnit) { var keyword = mathOperationsContainer.GetKeywordOrDefault(new OperationCharacteristics(expressionItem, operationType)); if (!string.IsNullOrEmpty(keyword)) { expressionUnit = new OperationExpressionUnit(expressionItem, keyword); return(true); } var leftBracketExpressionUnit = new LeftBracketExpressionUnit(); if (expressionItem == leftBracketExpressionUnit.Keyword) { expressionUnit = leftBracketExpressionUnit; return(true); } var rightBracketExpressionUnit = new RightBracketExpressionUnit(); if (expressionItem == rightBracketExpressionUnit.Keyword) { expressionUnit = rightBracketExpressionUnit; return(true); } expressionUnit = default(ExpressionUnit); return(false); }