C# 三角函数调车场算法
我正在用C#实现调车场算法。虽然它能很好地解析带有符号(+、*-/和^)的数学表达式,但由于某些原因,它不适用于正余弦函数。比如,如果我尝试计算sin(45),我得到0.707106。 但是当我试图解析表达式时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
我遵循了本文中提到的所有步骤。我已经尝试这几天了,但我无法使它完美地工作。这里是主要的解析函数
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() + " ";
}
}