C# 三角函数调车场算法

C# 三角函数调车场算法,c#,parsing,mathematical-expressions,shunting-yard,C#,Parsing,Mathematical Expressions,Shunting Yard,我正在用C#实现调车场算法。虽然它能很好地解析带有符号(+、*-/和^)的数学表达式,但由于某些原因,它不适用于正余弦函数。比如,如果我尝试计算sin(45),我得到0.707106。 但是当我试图解析表达式时 我遵循了本文中提到的所有步骤。我已经尝试这几天了,但我无法使它完美地工作。这里是主要的解析函数 private void parse() { //scan the input string for (int j = 0; j < input.Length

我正在用C#实现调车场算法。虽然它能很好地解析带有符号(+、*-/和^)的数学表达式,但由于某些原因,它不适用于正余弦函数。比如,如果我尝试计算sin(45),我得到0.707106。 但是当我试图解析表达式时



我遵循了本文中提到的所有步骤。我已经尝试这几天了,但我无法使它完美地工作。这里是主要的解析函数

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

            }

        }
    }
}
//有毛病的

   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
就这些。谁能告诉我我做错了什么

编辑:

以下是IshigherRecedDance函数和进程枚举 :

既然这些三角函数是单参数函数,那么它们是要用其他逻辑来解析呢,还是这个调车场算法也能用这些函数来解析呢

关于。

如果您使用此库: 您可以使用此语法来解析表达式

Digit: (?<Digit>[0-9]+('.'[0-9]+)?);
(?<Trig>): 'sin(' Expr ')' / 'cos(' Expr ')';
Value:  Digit / Trig / '(' Expr ')';
(?<Product>): Value ((?<Symbol>'*' / '/') Value)*;
(?<Sum>): Product ((?<Symbol>'+' / '-') Product)*;
(?<Expr>): Sum ;
数字:(?[0-9]+('.[0-9]+);
(?):“sin('Expr')”/“cos('Expr')”;
值:Digit/Trig/'('Expr');
(?):值((?'*'/'/')值)*;
(?):乘积((?“+”/“-”)乘积)*;
(?):总和;
在这里进行测试:

cos(25)+cos(15+sin(25.333))+3

(((12/3)+5-2*(81/9))+1))

努吉:

安装包NPEG


查看布尔代数AST的示例计算。

这里有一系列问题,但主要问题是您将函数视为运算符,尽管它们不是(本质上,您将堆栈称为“运算符”,好像这是唯一可以在堆栈上的东西,而不是真的)。特别是,该科:

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 (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]));
}

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

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() + " ";
    }

}

我立刻发现,您的
sin
工作示例没有括号,但失败的示例有括号。这就是问题所在吗?或者,您可能需要调试两个运算符的简单情况,其中只有一个是
sin
,例如使用
2+sin 30
作为输入。@L.B我已经将角度转换为弧度。@AakashM我已经编辑了线程。请检查线程的底部。嗯,Sin(45)+Cos(45)(或sin45+cos45)的正确后缀是
45sin45cos+
,而不是
45sin45cos
,如您的两个示例所示。这是表达式的后缀:Cos(45+Sin(45))。由于括号“(..”,优先级对函数没有意义。
Digit: (?<Digit>[0-9]+('.'[0-9]+)?);
(?<Trig>): 'sin(' Expr ')' / 'cos(' Expr ')';
Value:  Digit / Trig / '(' Expr ')';
(?<Product>): Value ((?<Symbol>'*' / '/') Value)*;
(?<Sum>): Product ((?<Symbol>'+' / '-') Product)*;
(?<Expr>): Sum ;
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 (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]));
}
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() + " ";
    }

}