В настоящее время я пишу импретер для простых математических выражений (константы и простая арифметика).
У меня возникла проблема с построением дерева выражения из выражения в формате постфикса. То, что я сделал, отлично работает в большинстве сценариев, но не в этом примере из Википедии.
Если я оцениваю выражение 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3
, я получаю результат 3,0001220703125
, хотя результат должен быть 3,001953125
. Причина этого, по-видимому, в том, что дерево выражений выглядит как 3+((4*2)/((1-5)^(2^3)))
вместо (3+((4*2)/(((1-5)^2)^3)))
.
Постфиксная запись исходного выражения выглядит как 3 4 2 * 1 5 − 2 3 ^ ^ / +
Есть предложения, как получить дерево выражений таким, каким я хочу его видеть?
Ниже приведен постфикс кода дерева выражений и некоторые тесты, написанные на C#, но не требующие пояснений.
public MathExpression Parse()
{
var tokens = this.ToPostFix(_tokens);
var stack = new Stack<MathExpression>();
foreach(token in tokens)
{
if(token.IsOperand())
{
// Push the operand on the stack.
stack.Push(new ConstantExpression(token.Value));
}
else
{
Debug.Assert(token.Type == TokenType.Operator, "Expected operator.");
var op = (Operator)token.Value;
var right = stack.Pop();
var left = stack.Pop();
var expression = new ArithmeticExpression(op, left, right);
stack.Push(expression);
}
}
Debug.Assert(stack.Count == 1, "More than one expression on stack.");
return stack.Pop();
}
И немного тестов:
[Test]
public void Wikipedia_Example_Can_Be_Evaluated()
{
var expected = 3+4*2/(1-5)^2^3; // 3,001953125
var actual = MathExpression.Parse("3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3")
.Evaluate(); // 3,0001220703125
Assert.AreEqual(expected, actual); // Not equal :(
}
[Test]
public void Can_Convert_To_Prefix()
{
string expected = "3 4 2 * 1 5 − 2 3 ^ ^ / +"
string actual = MathExpression.ToPostFix("3+4*2/(1-5)^2^3")
Assert.AreEqual(expected, actual); // Works as expected
}