具有三角函数的调车场算法 [英] shunting yard algorithm with trigonometric functions

查看:53
本文介绍了具有三角函数的调车场算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正致力于在 C# 中实现调车场算法.虽然它用符号(+、*-/和 ^)解析数学表达式非常好.但由于某种原因它不适用于正弦余弦函数.例如,如果我尝试计算 sin(45) 我得到 0.707106 .但是当我尝试解析像

I am working on implementing shunting yard algorithm in C#. Although it parses mathematical expressions with symbols( + , * - / and ^) pretty well.But for some reason it is not working for sine cosine functions . Like for example if I try to calculate sin(45) I get 0.707106 . But when I try to parse expression like

   sin(25)+cos(15+sin(25))+3  it gives me 0.43756   (Correct answer is: 2.19106879911)

<小时>

    sin(45)+cos(45) it gives me 0.715779      (Correct answer is: 1.414)

我已按照本文维基百科中提到的所有步骤进行操作.我已经尝试了几天,但我无法让它完美地工作.这里是主要的解析函数

I have followed all the steps that are mentioned in this article at Wikipedia . I have trying this for a few days now but I am unable to make it work perfectly. Here is the main parsing function

    private void parse()
{
    //scan the input string
    for (int j = 0; j < input.Length; j++)
    {

        if (Char.IsDigit(input[j])) //if its a number
        {
            string number = extractNumber(input, j);  //extracts multiple digit number
            j = currentposition; //increment the counter according to length of the digit
            postfix += number + " ";
            Console.WriteLine(postfix);
        }
            //if its a function character
        else if(Char.IsLetter(input[j]) )
        {
            //its a letter
            string function = getFunction(j); //get the function name
            operators.Push( function );
            j = currentposition;

        }
        else if(input[j] == ',') //if its a comma
        {
            while(operators.Peek() != "(")
            {
                postfix += input[j] + " ";

            }

        }
        else if (IsAnOperator(input[j])) // if we have got an operator
        {
           if (operators.Count != 0 && IsHigherPrecedence(operators.Peek().ToCharArray()[0], input[j]))
            {
                while ( ( operators.Count != 0 && IsHigherPrecedence(operators.Peek().ToCharArray()[0], input[j]) )  )
                { 
                    postfix += operators.Pop() + " "; 

                }
            }

              operators.Push(Char.ToString(input[j]));
        }
        else if (input[j] == '(')
            operators.Push(Char.ToString(input[j]));
        else if (input[j] == ')')
        {
            while (operators.Count != 0 && operators.Peek() != "(")
                postfix += operators.Pop() + " ";
            operators.Pop();
        }


    } // end for loop

        while(operators.Count > 0 )
            postfix +=operators.Pop() + " ";

     //Conversion Logic  (postfix to final answer )

        postfixtokens.AddRange( postfix.Split(' ') ) ;

    for (int j = 0; j < postfixtokens.Count-1; j++)
    {

        if (IsAnOperator(postfixtokens[j][0]) && basket.Count > 1)
        {

            Double second = Double.Parse( basket.Pop() );

            Double first = Double.Parse(basket.Pop() );
            char op = postfixtokens[j][0];
            Double result = ApplyOperation(op,second, first);
         //   Console.WriteLine("{0} {1} {2} = {3}", first, op, second, result);
            basket.Push( result.ToString());
        }
        else if (IsAnOperator(postfixtokens[j][0]) && basket.Count == 1)
        {

            Double second = Double.Parse(basket.Pop());
            Double first = 0.0;
            char op = postfixtokens[j][0];

            Double result = ApplyOperation(op, second, first);

         //   Console.WriteLine("{0} {1} {2} = {3}", first, op, second, result);
            basket.Push(result.ToString() );
        }
        else if (Char.IsDigit(postfixtokens[j][0]))
        {
            basket.Push( postfixtokens[j] );
        }
        else if( isAFunction(postfixtokens[j]) )
        {
            //if its a single argument function
            if (AllowedFunctions[postfixtokens[j]] == 1)
            {
                //single arg logic
                if (postfixtokens[j] == "sin")
                {
                    Double result =  Math.Sin( Double.Parse(basket.Pop() )*Math.PI/180.0 );
                    //result = Math.PI / 180;
                    basket.Push(result.ToString());
                }
                else if (postfixtokens[j] == "cos")
                {
                       Double result =  Math.Cos( Double.Parse(basket.Pop() )*Math.PI/180.0 );
                    //result = Math.PI / 180;
                    basket.Push(result.ToString());
                }

            }

        }
    }
}

此外,这是程序的输出:

Moreover, Here is the output of the program:

   Input: 3+4*2/(1-5)^5^10
   PostFix: 3 4 2 * 1 5 - 5 10 ^ ^ / +
   Answer: 3


   Input: 2+4
   PostFix: 2 4 +
   Answer: 6

   Input Expression: -5-4
   Input: -5-4
   PostFix: 5 - 4 -
   Answer: -9

   Input: -4+3
   PostFix: 4 - 3 +
   Answer: -1

   Input Expression: 4^(4^4)
   Input: 4^(4^4)
   PostFix: 4 4 4 ^ ^
   Answer: 1.34078079299426E+154

   Input: sin45
   PostFix: 45 sin
   Answer: 0.707106781186547  (correct)

//错误的

   Input: sin(25)+cos(15+sin(25))+3
   PostFix: 25 15 25 sin + 3 + cos + sin
   Answer: 0.437567038002202

   Input: sin(45)+cos(45)
   PostFix: 45 45 cos + sin
   Answer: 0.71577935734684

新案例:

    Input: sin45+cos45
    PostFix: 45 45 cos + sin
    Answer: 0.71577935734684

    Input: 2+sin30
    PostFix: 2 30 sin +
    Answer:2.5

    Input: sin30+2
    PostFix: 30 2 + sin
    Answer: 0.529919264233205

仅此而已.谁能指出我做错了什么.

Thats all.Can anybody point me what I am doing wrong.

这里是 IsHigherPrecedance 函数和优先级枚举:

Here is the IsHigherPrecedance function and precedance enum :

    public enum Precedance { Plus =1,Minus=1,Multiply=2,Divide=2,Exponent=3,Unary = 4,Parenthesis=5 };
   private bool IsHigherPrecedence(char a, char b)
   {
    Precedance f = getPrecedance(a);
    Precedance s = getPrecedance(b);


    if (f >= s)
        return false;
    else
        return true;
   }
  public Precedance getPrecedance(char a)
{

    if (a == '+')
        return Precedance.Plus;
    else if (a == '-')
        return Precedance.Minus;
    else if (a == '*')
        return Precedance.Multiply;
    else if (a == '/')
        return Precedance.Divide;
    else if (a == '^')
        return Precedance.Exponent;
    else if (Char.IsLetter(a))
        return Precedance.Unary;
    else if (a == '(' || a == ')')
        return Precedance.Parenthesis;
    else
        return Precedance.Plus;
}

既然这些三角函数是单参数函数,它们是否会用其他一些逻辑进行解析,或者这种调车算法是否也适用于这些函数?

Now that these trigonometric function are single argument function, are they going to be parsed with some other logic or does this shunting yard algo works with such functions as well as well?

问候.

推荐答案

这里有很多问题,但主要的问题是您将函数视为运算符,尽管它们不是(本质上是您调用您的堆栈运算符"就好像这是唯一可以在它上面的东西,而不是真的).特别是这个分支:

There are a copule of problems here, but the primary one is that you are treating functions as operators, though they are not (intrinsic to this is that you call your stack "operators" as though that is the only thing that can be on it, not true). In particular, this branch:

else if (IsAnOperator(input[j])) // if we have got an operator
{
    if (operators.Count != 0 && IsHigherPrecedence(operators.Peek().ToCharArray()[0], input[j]))
    {
        while ( ( operators.Count != 0 && IsHigherPrecedence(operators.Peek().ToCharArray()[0], input[j]) )  )
        { 
            postfix += operators.Pop() + " "; 
        }
    }
    operators.Push(Char.ToString(input[j]));
}

需要检查operators"堆栈上的内容是否实际上是一个运算符:

needs to check to see if what's on the "operators" stack is actually an operator:

else if (IsAnOperator(input[j])) // if we have got an operator
{
    while (operators.Count != 0 
        && IsAnOperator(operators.Peek().ToCharArray()[0])
        && IsHigherPrecedence(operators.Peek().ToCharArray()[0], input[j]))
    {
       postfix += operators.Pop() + " "; 
    }
    operators.Push(Char.ToString(input[j]));
}

<小时>

其他问题包括处理逗号的分支:


Other issues include the branch that handles commas:

else if (input[j] == ',') //if its a comma
{
    while (operators.Peek() != "(")
    {
        // this isnt right, but its not the problem
        postfix += input[j] + " ";
        // should be this:
        postfix += operators.Pop() + " ";
    }

}

这篇关于具有三角函数的调车场算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆