Blog (9)
Komentarze (73)
Recenzje (0)
@pat.wasiewiczPiszemy trochę bardziej złożony kalkulator w C#.NET - #3

Piszemy trochę bardziej złożony kalkulator w C#.NET - #3

17.04.2013 23:57

Przypomnienie

Witam ponownie po dłuższej przerwie. Przypomnę pierwsze dwa wpisy dot. kalkualtora: Część1 : stworzyliśmy klasę Expression Część 2 : pokazaliśmy jak przekształcić wyrażenie zapisane postfiksowo w string'u do klasy Expression

Expression z notacji infiksowej

Schemat będzie wyglądał tak: zmieniamy wyrażenie napisane infiksowo na postfiksowo a potem korzystając z metody napisanej w części #2 dostaniemy instancję klasy Expression.

Algorytm zmiany wyrażenia infiksowego do ONP znajdziemy na wikipedii.

Zacznijmy od metody pomocniczej:

        private static byte GetPriority(char sign)
        {
            switch (sign)
            {
                case '(':
                    return 0;

                case ')':
                case '+':
                    return 1;

                case '*':
                case '/':
                    return 2;

                default:
                    throw new ArgumentException("Błędny operator!");
            }

        }

Teraz już właściwy kod:

public static Expression FromInfix(string input)
{
    var output = new StringBuilder();
    var operators = new Stack<char>();
    var arguments = Regex.Split(input, @"\s+");

    foreach (var sym in arguments)
    {
        // jeżeli argument
        if (!Regex.IsMatch(sym, @"^[\+|\*|/|(|)]$"))
        {
            output.Append(" ");
            output.Append(sym);
        }
        else
        {
            // dostaliśmy operator
            var symChar = Convert.ToChar(sym);
            switch (symChar)
            {
                case '(':
                    operators.Push(symChar);
                    break;

                case ')':
                    var leftBracket = operators.Pop();
                    while (!leftBracket.Equals('('))
                    {
                        output.Append(" ");
                        output.Append(leftBracket);

                        leftBracket = operators.Pop();
                    }
                    break;

                case '*':
                case '+':
                case '/':
                    // stos pusty albo operator na wierzchołku ma mniejszy priorytet
                    if (operators.Count == 0 || GetPriority(operators.Peek()) < GetPriority(symChar))
                    {
                        operators.Push(symChar);
                        break;
                    }

                    var oper = operators.Peek();

                    // zdejmij wszystkie operatory o wiekszym bądź równym priorytecie i zapisz na wyjściu
                    while (GetPriority(oper) >= GetPriority(symChar) && operators.Count > 0)
                    {
                        output.Append(" ");
                        output.Append(oper);

                        operators.Pop();
                        oper = operators.Peek();
                    }

                    // wrzuć na stos aktualny operator
                    operators.Push(symChar);
                    break;
            }
        }
    }

    // jeśli jakiś operator został na stosie, też go zapisz na wyjściu
    if (operators.Count == 1)
    {
        output.Append(" ");
        output.Append(operators.Peek());
    }

    // usuń pierwszą spację
    output = output.Remove(0, 1);
    return FromOnp(output.ToString());
}

Teraz możemy przetesować nasz kod:

var expr5 = Expression.FromInfix("( 12 + 3 ) * x");
Console.Write(
    "Wyrażenie wygląda tak: {0}\nJego wartość to {1}\n" + "Pochodna to {2}\nCałka od 1 do 2 to {3}\n\n",
    expr5,
    expr5.Calculate(4),
    expr5.Derivative(),
    expr5.Integral(1, 2));

Co da nam wynik:

Wynik
Wynik
Wybrane dla Ciebie
Komentarze (1)