/// <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 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); }