我正在C#中实现分流码算法。虽然它很好地用符号(+,* - /和^)解析数学表达式。但由于某种原因它不适用于正弦余弦函数。例如,如果我尝试计算罪(45),我得到0.707106。 但是当我尝试解析像
这样的表达式时 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)
我已按照本文at Wikipedia中提到的所有步骤进行操作。我已经尝试了几天,但我无法让它完美地运作。这是主要的解析功能
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: 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
多数民众赞成。任何人都可以指出我做错了什么。
编辑:
这是IsHigherPrecedance函数和precedance枚举 :
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;
}
既然这些三角函数是单个参数函数,它们是否会被其他一些逻辑解析,或者这个调车场算法是否也可以使用这些函数?
问候。
答案 0 :(得分:3)
这里有一些问题,但主要的一点是你将函数视为运算符,虽然它们不是(内在的是你称之为堆栈的“运算符”,好像这是唯一能够坚持下去,不是真的)。特别是这个分支:
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() + " ";
}
}
答案 1 :(得分:0)
如果您使用此库:https://github.com/leblancmeneses/NPEG 你可以使用这个语法来解析你的表达。
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 ;
在这里测试一下: http://www.robusthaven.com/blog/parsing-expression-grammar/npeg-language-workbench
cos(25)+cos(15+sin(25.333))+3
((((12/3)+5-2*(81/9))+1))
nuget:
安装包NPEG
查看布尔代数的AST样本评估。