/// <summary>
        /// Takes in a string that contains an expression and returns
        /// a boolean value if the expression is valid, i.e. it has
        /// an operator and the appropriate number of operands.
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public static bool IsComplete(string func)
        {
            //First reverse expression back to normal postfix
            string funcNormal = StringFunctions.ReverseString(func);
            string funcEval   = StringFunctions.ReplaceConstants(funcNormal, Math.Tan(2 + Math.Exp(10)) + Math.PI);

            //Simplest way is to try to evaluate it and see what happens
            try
            {
                /*
                 * Pick a value that's extremely unlikely to cause
                 * any issues other than if the expression is complete
                 * or not.
                 */
                Calculator.EvaluatePostFix(funcEval);
                return(true);
            }
            catch
            {
                return(false);
            }
        }
示例#2
0
        /// <summary>
        /// Calculates the limit as it approaches the value from both
        /// the left and right and averages between the two answers
        /// until either the x values get too close or the threshold
        /// is reached.
        /// </summary>
        /// <param name="func"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public static double EvaluateLimit(string func, double limit)
        {
            //Constants
            const double thresh   = 1e-3;
            const double thresh_x = 1e-5;
            const double delta    = 1e-4;

            //Initial step to initialize everything
            double x_l       = limit - 1;
            double x_r       = limit + 1;
            double left_ans  = Calculator.Calculate(func, x_l);
            double right_ans = Calculator.Calculate(func, x_r);
            double del       = Math.Abs(right_ans - left_ans);
            double del_x     = Math.Abs(x_l - x_r);
            double ans       = (left_ans + right_ans) / 2;

            //Infinite limits
            if (double.IsInfinity(limit))
            {
                //Deal with undefined fractions e.g. 1/inf with L'Hopital
                if (double.IsNaN(ans))
                {
                    //Get index of first outer division symbol
                    int index = StringFunctions.FindOuterSlash(func);

                    //Split into numerator and denominator
                    string num = func.Substring(0, index);
                    string den = func.Substring(index + 1, func.Length - 2);

                    //Take the derivate of the numerator and denominator
                    string numDer = DerivativeCalculator.Derivative(num);
                    string denDer = DerivativeCalculator.Derivative(den);

                    string tot = numDer + "/" + denDer;

                    return(EvaluateLimit(tot, limit));
                }
                else
                {
                    return(ans);
                }
            }

            //Loop until confident limit either converges or DNC
            while (true)
            {
                //If x values too close and still not converged, limit DNC
                if ((del < thresh) & (del_x < thresh))
                {
                    return(ans);
                }
                if (del_x < thresh_x)
                {
                    return(double.PositiveInfinity);
                }

                //Step to next values
                x_l += delta;
                x_r -= delta;

                //Calculate function at current step
                left_ans  = Calculator.Calculate(func, x_l);
                right_ans = Calculator.Calculate(func, x_r);

                //Get differences for break conditions
                del   = Math.Abs(right_ans - left_ans);
                del_x = Math.Abs(x_l - x_r);

                //Take average of two as current solution
                ans = (left_ans + right_ans) / 2;

                //Console.WriteLine(x_l + " " + x_r + " " + del_x + " " + left_ans + " " + right_ans + " " + del + " " + ans);
            }
        }
示例#3
0
        /// <summary>
        /// Debugs the derivative function, checking
        /// against solutions found from wolframalpha.com
        /// in order to compute L'Hopital's rule for
        /// taking limits that result in an indeterminate
        /// form.
        /// </summary>
        public static void DebugDerivative()
        {
            Console.WriteLine("Debugging derivative methods:");

            //Functions to test derivative of
            string[] funcList = { "(x+1)^(x+1)", "(x+2)^2",     "x^5",
                                  "2^(x+2)",     "x+x+x-x",     "ln(1/x)",
                                  "(x+2)/(x-5)", "(x*2)+(x/5)", "2+(x+2)^2+2^x",
                                  "e^x",         "cos(2)",      "cos(x)",       "cos(x^2)",
                                  "x",           "-x",          "-2^x",
                                  "sin(5)",      "sin(x)",      "sin(x^2)",
                                  "tan(5)",      "tan(x)",      "tan(x^2)",
                                  "log5(5)",     "log5(x)",     "log5(x^2)",
                                  "arccos(5)",   "arccos(x)",   "arccos(x^2)",  //Everything on and below this was done with x = 0.5
                                  "arctan(5)",   "arctan(x)",   "arctan(x^2)",
                                  "arcsin(5)",   "arcsin(x)",   "arcsin(x^2)",
                                  "sec(5)",      "sec(x)",      "sec(x^2)",
                                  "csc(5)",      "csc(x)",      "csc(x^2)",
                                  "cot(5)",      "cot(x)",      "cot(x^2)",
                                  "sqrt(5)",     "sqrt(x)",     "sqrt(x^2)",
                                  "abs(5)",      "abs(x)",      "abs(cos(x))",  };

            //From wolframalpha
            string[] correctAns = { "56.6625",  "8",         "80",
                                    "11.09035", "2",         "-0.5",
                                    "-7/9",     "2.2",       "10.7726",
                                    "7.38905",  "0",         "-0.90929",  "3.0272",
                                    "1",        "-1",        "-2.77258",
                                    "0",        "-0.416146", "-2.614574",
                                    "0",        "5.774399",  "9.36220048",
                                    "0",        "0.310667",  "0.621334",
                                    "0",        "-1.1547",   "-1.0328",   //Everything on and below this was done with x = 0.5
                                    "0",        "0.8",       "0.941176",
                                    "0",        "1.1547",    "1.0328",
                                    "0",        "0.622508",  "0.263535",
                                    "0",        "-3.81809",  "-15.8296",
                                    "0",        "-4.35069",  "-16.3375",
                                    "0",        "0.707107",  "1",
                                    "0",        "1",         "-0.479426", };

            //Run through test suite
            for (int i = 0; i < funcList.Length; i++)
            {
                //Attempt to calculate derivative, throw error if fails
                try
                {
                    string func = funcList[i];
                    string ans  = correctAns[i];

                    //Remove any whitespace for parsing
                    //func = "log_5(x)";

                    //Calculate limits and output answer
                    //double test = LimitCalc.EvaluateLimit(func, 2);
                    //Console.WriteLine("Limit as x->" + 2 + " of " + func + " = " + Math.Round(test, 3) + " ans: " + ans);

                    //Replace constants, convert to postfix, take derivative
                    string analytic_func = StringFunctions.ReplaceConstants(func, 0, false);
                    string funcPostFix   = Calculator.Convert2Postfix(analytic_func);
                    string test          = DerivativeCalculator.Derivative(funcPostFix);

                    //Choose what value to evaluate at based on function domain
                    int index = Array.IndexOf(funcList, "arccos(5)");
                    if (i < index)
                    {
                        Console.WriteLine(func + ": " + Calculator.Calculate(test, 2) + " ans: " + ans);
                    }
                    else
                    {
                        Console.WriteLine(func + ": " + Calculator.Calculate(test, 0.5) + " ans: " + ans);
                    }
                }
                catch
                {
                    string func = funcList[i];

                    Console.WriteLine("Error with derivative of: " + func);
                }
            }
        }
示例#4
0
        /// <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);
        }