/// <summary> /// Converts a given postfix array to a infix expression. /// </summary> /// <param name="postfixExp"></param> /// <returns></returns> public static string Convert2Infix(string[] postfixExp) { Stack <string> tokenStack = new Stack <string>(); List <string> postfixList = new List <string>(); //Operator lists for different number of operands List <string> unaryOperators = new List <string>(); List <string> binaryOperators = new List <string>(); OperatorFunctions.UnaryOperators(unaryOperators); OperatorFunctions.BinaryOperators(binaryOperators); //Recreate postfix list for (int i = 0; i < postfixExp.Length; i++) { postfixList.Add(postfixExp[i]); } postfixList.Reverse(); //Iterate over all tokens in postfix expression foreach (string token in postfixList) { //Binary operators if (binaryOperators.Any(token.Contains)) { string x = tokenStack.Pop(); string y = tokenStack.Pop(); string exp = "(" + y + token + x + ")"; tokenStack.Push(exp); } //Unary operators else if (unaryOperators.Any(token.Contains)) { string x = tokenStack.Pop(); string exp = "(" + token + "(" + x + ")" + ")"; tokenStack.Push(exp); } /* * Add Numbers directly to string, the first * one doesn't need a buffer space in-between */ else { tokenStack.Push(token); } } return(tokenStack.Pop()); }
/// <summary> /// Tests for finding the limit of many /// functions and comparing with results /// found from wolframalpha.com /// </summary> public static void DebugLimit() { Console.WriteLine("Debugging limit methods:"); string limStr, limPostFix; double lim = 0; //Operator dictionary to define order of operations Dictionary <string, int> operators = new Dictionary <string, int>(); OperatorFunctions.Operators(operators); //Test as many different operators I can think of - probably don't need test suite for this string[] funcList = { "-5 + (((sqrt(x) - x!)^2 / (x^2 * 5 + 3 * csc(cos(x)))) % 2) + abs(x) + ln(x) + arctan(x)", "-(x+5)", "x + -5","(-x)", "-x + 5", "log2(x)" }; double[] correctAns = { 3.166983673, -10, 0, -5, 0, 0, }; limStr = "5"; for (int i = 0; i < funcList.Length; i++) { string func = funcList[i]; double ans = correctAns[i]; //Create list of elements in limit to test for operators List <string> limList = new List <string>(); limList = StringFunctions.Convert2List(limStr); //Check for operators in limit and convert appropriately if (limList.Any(operators.ContainsKey)) { limStr = StringFunctions.ReplaceConstants(limStr); limPostFix = Calculator.Convert2Postfix(limStr); lim = Calculator.EvaluatePostFix(limPostFix); } else { limStr = StringFunctions.ReplaceConstants(limStr); lim = double.Parse(limStr); } //Remove any whitespace for parsing func = func.Replace(" ", ""); //Calculate limits and output answer double test = LimitCalc.EvaluateLimit(func, lim); Console.WriteLine("Limit as x->" + lim + " of " + func + " = " + Math.Round(test, 3) + " ans: " + ans); } }
/// <summary> /// Takes a given postfix expression and evaluates it /// and returns the value to the main program to test /// for convergence. /// </summary> /// <param name="postfixExp"></param> /// <returns></returns> public static double EvaluatePostFix(string postfixExp) { string x, y, ans; string[] postfixArray = postfixExp.Split(null); Stack <string> tokenStack = new Stack <string>(); //Operator lists for different number of operands List <string> unaryOperators = new List <string>(); List <string> binaryOperators = new List <string>(); OperatorFunctions.UnaryOperators(unaryOperators); OperatorFunctions.BinaryOperators(binaryOperators); //Iterate over all tokens in postfix expression foreach (string token in postfixArray) { if (binaryOperators.Any(token.Contains)) { //Evaluate functions that take two arguments y = tokenStack.Pop(); x = tokenStack.Pop(); ans = OperatorFunctions.EvaluateExp(x, y, token).ToString(); tokenStack.Push(ans); } else if (unaryOperators.Any(token.Contains)) { //Evaluate functions that only take a single argument x = "temp"; y = tokenStack.Pop(); ans = OperatorFunctions.EvaluateExp(x, y, token).ToString(); tokenStack.Push(ans); } else { tokenStack.Push(token); } } //Last thing on stack is the answer ans = tokenStack.Pop(); return(double.Parse(ans)); }
/// <summary> /// Takes in user input for a function and a value to evaluate the limit at /// and returns the value of the function if it converges or returns /// "inf" if it diverges. /// </summary> /// <param name="args"></param> private static void RunLimitCalc() { string func, limStr, limPostFix; double lim = 0, ans; //Operator dictionary to define order of operations Dictionary <string, int> operators = new Dictionary <string, int>(); OperatorFunctions.Operators(operators); //Let user keep entering functions and limits as they desire while (true) { //User input Console.WriteLine("Input f(x): "); func = Console.ReadLine(); Console.WriteLine("Input limit: "); limStr = Console.ReadLine(); //Create list of elements in limit to test for operators List <string> limList = new List <string>(); limList = StringFunctions.Convert2List(limStr); //Check for operators in limit and convert appropriately if (limList.Any(operators.ContainsKey)) { limStr = StringFunctions.ReplaceConstants(limStr); limPostFix = Calculator.Convert2Postfix(limStr); lim = Calculator.EvaluatePostFix(limPostFix); } else { limStr = StringFunctions.ReplaceConstants(limStr); lim = double.Parse(limStr); } //Remove any whitespace for parsing func = func.Replace(" ", ""); //Calculate limits and output answer ans = EvaluateLimit(func, lim); Console.WriteLine("Limit as x->" + lim + " of " + func + " = " + Math.Round(ans, 3)); Console.ReadLine(); } }
/// <summary> /// Takes in a string that contains an expression and returns /// a boolean value if the expression is singular, i.e. it /// does not contain any operators. /// </summary> /// <param name="func"></param> /// <returns></returns> public static bool IsSingular(string[] func) { //Operator lists for different number of operands Dictionary <string, int> operators = new Dictionary <string, int>(); OperatorFunctions.Operators(operators); //Skip placeholder strings if (func.Contains("temp")) { return(false); } //Check all tokens for operators foreach (string token in func) { if (operators.Any(p => p.Key == token)) { return(false); } } return(true); }
/// <summary> /// This function takes an analytic expression and determines /// whether a "-" is a subtraction of two values or a negation /// of one value. Substitutes negations with 0 - value instead. /// </summary> /// <param name="Exp"></param> /// <returns></returns> public static List <string> ReplaceNegatives(List <string> Exp) { //Deep clone list for constant length to iterate over List <string> ExpOut = new List <string>(); //ExpOut = DeepCloneList(Exp); ExpOut = Exp; int StrLen = Exp.Count(); //Operator dictionary Dictionary <string, int> operators = new Dictionary <string, int>(); OperatorFunctions.Operators(operators); for (int i = 0; i < ExpOut.Count() - 1; i++) { if ((operators.Any(p => p.Key == ExpOut[i])) & (ExpOut[i + 1] == "-")) { //Case a + -b //ExpOut.Insert(i + 1, "0"); ExpOut.Insert(i + 1, "("); ExpOut.Insert(i + 2, "0"); ExpOut.Insert(i + 5, ")"); i += 3; } else if ((ExpOut[i] == "(") & (ExpOut[i + 1] == "-")) { //Case (-a) //ExpOut.Insert(i + 1, "0"); ExpOut.Insert(i + 1, "("); ExpOut.Insert(i + 2, "0"); ExpOut.Insert(i + 5, ")"); i += 3; } else if ((i == 0) & (ExpOut[i] == "-")) { //Case -a + b //ExpOut.Insert(i , "0"); ExpOut.Insert(i, "("); ExpOut.Insert(i + 1, "0"); ExpOut.Insert(i + 4, ")"); i += 2; } else if ((ExpOut[i] == "-") & (ExpOut[i + 1] == "(") & (i == 0)) { //Case -(a + b) //ExpOut.Insert(i, "0"); ExpOut.Insert(i, "("); ExpOut.Insert(i + 1, "0"); ExpOut.Insert(i, "0"); i += 2; } //Relic - might not be needed if (((ExpOut[i] == "-") & (ExpOut[i + 1] == "~")) | ((ExpOut[i] == "~") & (ExpOut[i + 1] == "-"))) { //Case ~-a or -~a ExpOut.RemoveRange(i, 2); } //Relic - might not be needed if (((ExpOut[i] == "~") & (ExpOut[i + 1] == "~")) | ((ExpOut[i] == "-") & (ExpOut[i + 1] == "-"))) { //Case ~~a or --a ExpOut.RemoveRange(i, 2); } /* ################ ## Old Method ## ################ ################ ################if ((operators.Any(p => p.Key == ExpOut[i])) & (ExpOut[i + 1] == "-")) ################{ ################//Case a + -b ################ExpOut[i + 1] = "~"; ################} ################if ((ExpOut[i] == "(") & (ExpOut[i + 1] == "-")) ################{ ################//Case (-a) ################ExpOut[i + 1] = "~"; ################} ################if ((i == 0) & (ExpOut[i] == "-")) ################{ ################//Case -a + b ################ExpOut[i] = "~"; ################} ################if ((ExpOut[i] == "-") & (ExpOut[i + 1] == "(") & (i == 0)) ################{ ################//Case -(a + b) ################ExpOut[i] = "~"; ################} ################if (((ExpOut[i] == "-") & (ExpOut[i + 1] == "~")) | ################((ExpOut[i] == "~") & (ExpOut[i + 1] == "-"))) ################{ ################//Case !-a or -!a ################ExpOut.RemoveRange(i, 2); ################} ################if (((ExpOut[i] == "~") & (ExpOut[i + 1] == "~")) | ################((ExpOut[i] == "-") & (ExpOut[i + 1] == "-"))) ################{ ################//Case !!a or --a ################ExpOut.RemoveRange(i, 2); ################} */ } return(ExpOut); }
/// <summary> /// Converts a given infix expression to a postfix expression /// to calculate the values used for testing convergence of /// limits. /// </summary> /// <param name="infixExp"></param> /// <returns></returns> public static string Convert2Postfix(string infixExp) { List <string> infixList = new List <string>(); string postfixExp = ""; Stack <string> tokenStack = new Stack <string>(); tokenStack.Push("("); //Operator dictionary to define order of operations Dictionary <string, int> operators = new Dictionary <string, int>(); OperatorFunctions.Operators(operators); //Convert infix expression to an array of strings infixList = StringFunctions.Convert2List(infixExp); infixList = StringFunctions.ReplaceNegatives(infixList); infixList.Add(")"); //Iterate over all tokens in infix expression foreach (string token in infixList) { if (token == "(") { tokenStack.Push(token); } else if (token == ")") { /* * Add operators to string until left paren reached, * then pop left paren */ for (int i = 0; i <= tokenStack.Count(); i++) { if (tokenStack.Peek() == "(") { tokenStack.Pop(); break; } else { postfixExp += " " + tokenStack.Pop(); } } } else if (operators.Any(p => p.Key == token)) { /* * Add operators in stack >= current operator to string, * then push current operator to stack */ for (int i = 0; i <= tokenStack.Count(); i++) { if (tokenStack.Peek() == "(") { break; } else if (operators[tokenStack.Peek()] >= operators[token]) { postfixExp += " " + tokenStack.Pop(); } } tokenStack.Push(token); } else { /* * Add Numbers directly to string, the first * one doesn't need a buffer space in-between */ if (postfixExp.Length == 0) { postfixExp += token; } else { postfixExp += " " + token; } } } return(postfixExp); }
/// <summary> /// Takes in a reverse postfix array and recursively grabs /// an operator and two operands to be derivated such /// that they are all complete expressions. /// </summary> /// <param name=""></param> /// <returns></returns> private static string CompleteExpressions(string[] postfixArray) { //Operator lists for different number of operands List <string> unaryOperators = new List <string>(); List <string> binaryOperators = new List <string>(); OperatorFunctions.UnaryOperators(unaryOperators); OperatorFunctions.BinaryOperators(binaryOperators); //Initialize int i = 0; string token = postfixArray[0]; //Split between no, unary, and binary operators if (unaryOperators.Any(token.Contains)) { string A = postfixArray[1]; string B = "temp"; bool completeA = IsComplete(A); //Loop until complete expressons while (!completeA) { i++; if (!completeA) { A += " " + postfixArray[i + 1]; } //Recheck for completeness and increment completeA = IsComplete(A); } string[] ArrA = A.Split(' '); string[] ArrB = B.Split(' '); return(EvaluateDerivative(ArrA, ArrB, token)); } else if (binaryOperators.Any(token.Contains)) { string B = postfixArray[1]; string A = postfixArray[2]; bool completeA = IsComplete(A); bool completeB = IsComplete(B); //Loop until complete expressons while ((!completeA) || (!completeB)) { //Try to fix completeness if (!completeB) { B += " " + A; A = postfixArray[i + 3]; } else if (!completeA) { A += " " + postfixArray[i + 3]; } //Recheck for completeness and increment completeA = IsComplete(A); completeB = IsComplete(B); i++; } string[] ArrA = A.Split(' '); string[] ArrB = B.Split(' '); return(EvaluateDerivative(ArrA, ArrB, token)); } else { string[] tempList = { "temp" }; return(EvaluateDerivative(tempList, postfixArray, "temp")); } }