Практика: Арифметические выражения и калькуляторы
Скобочные выражения, Обратная польская запись, стековый калькулятор
Стеки
В этой лабораторной работе многократно будет использоваться стек, поэтому для начала предлагается освежить в памяти, как эта структура обычно выглядит на языке python.
Упражнение №1
Напишите программу, которая последовательно кладет в стек произвольный массив чисел, а затем распечатывает их , последовательно доставая, пока стек не пуст (например, набор (1,...,10)).
Правильные скобочные структуры
Известно, что скобочные выражения могут быть корректными и некорректными. Корректные - это такие, которые можно вычислить по правилам, если расставить между ними числа и знаки бинарных операций. Иными словами, интуитивно, такие. где зоны действия скобок разных типов не пересекаются(если есть скобки разных типов).
Упражнение №2
Написать программу, определяющую правильность введенного скобочного выражения, в котором используются скобки 3 видов: (), {}, /.
Арифметические выражения. Инфиксная, постфиксная и префиксная нотации
- Рассмотрим арифметическое выражение
- \begin{equation*} (2-3)*(12-10)+4/2 \end{equation*}
Его значение легко вычисляется и оказывается даже целым - это 0(не забываем правила приоритета операций!). Это привычная для нас форма записи арифметических выражений, в которой если операция бинарная (т.е. требует 2 аргументов, например, сложение, деление), то один аргумент пишется перед знаком операции, а другой - после неё. Такая форма записи называется инфиксной.
Нотация (способ записи), в которой операнды пишутся перед знаком операции - называется постфиксной или обратной польской.
Нотация. в которой операнды пишутся после знака операции - прямой польской или префиксной.
Например, уже рассмотренное выражение в обратной польской записи будет выглядеть как
\begin{equation*} 2 3 - 12 10 - * 4 2 / + \end{equation*}
После пары 2 и 3 стоит знак вычитания. После пары 12 и 10 - тоже. Далее стоит знак перемножения, потому что результаты этих двух операций надо умножить. Далее стоят 4 и 2 и после них знак деления. А после - знак сложения, показывающий, что результат предыдущего нужно сложить с результатом деления 4 на 2.
а в прямой польской как
\begin{equation*} + * - 2 3 - 12 10 / 4 2 \end{equation*}
Аналогичным образом, только теперь знак операции стоит перед операндами (или их описаниями в виде выражений в той же форме записи).
Упражнение №3
Перевести выражение
в прямую и обратную польские записи.
В общем и целом, любое выражение можно представить в виде структуры, называемой деревом(синтаксическим деревом в данном случае, поскольку оно отражает структуру выражения). Например, для разобранного выражения синтаксическое дерево будет выглядеть так:
Его конечные вершины, листья (из которых стрелки никуда не идут) - это операнды, а промежуточные (из которых идут стрелки)- операции. Прямая польская запись (префиксная) получается, если читать это дерево сверху вниз. Обратная (постфиксная) - если читать снизу вверх.
Стековый калькулятор
Стековый калькулятор - это устройство (реальное или виртуальное), которрое вычисляет значения арифметических выражений , записанный в постфиксной форме. Стековым он называется по понятным причинам: если нам встречается число - мы должны поместить его в стек; если знак опренрации - мы должны достать из стека столько чиссел, скольок необходимо для выполнения данной операции. Именно так и работает т.н. математический сопроцессор (например, в INtel8086+AMD64)- часть ЦП, отвечающая за операции над числами с плавающей запятой.
Упражнение №4
Реализовать стековый калькулятор на python. Написать программу, которая читает выражение в обратной польской нотации и считает его значение или пишет, что выражение составлено не корректно (если оно некорректно).
Сортировочная станция Дейкстры
Как нетрудно видеть: выражения в обратной польской записи удобны для чтения компьютером , но неудобны для чтения и составления людьми. Поэтому хотелось бы доверить труд составления постфиксной формы выражений по их привычной инфиксной форме компьютеру. Это можно сделать с помощью так называемого алгоритма сортировочной станции (Shunting Yard algorithm , придуман Э. Дейкстрой в 1961 году, см https://en.wikipedia.org/wiki/Shunting-yard_algorithm для трансляторов языка Algol60 https://ir.cwi.nl/pub/9251).
В следующем примере, взятом как раз из википедии, разбирается преобразование выражения
Есть сортировочная станция с 3 путями: 2 подъездных и 1 тупик. С правоого подъездного пути едут выражения: в каждом "вагоне" или операнд или знак операции. Операнды свободно проезжают в левый путь (образуя очередь), а операторы заезжают в тупик.
By Salix alba - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=10960619
Если приоритет входящего оператора ниже приоритета того, что навершине стека (на входе в тупик), то из стека достаётся оператор с большим приоритетом (на шаге g это умножение). То же самое происходит, если приооритет приходящего оператора равен приоритету такового на вершине стека, но тот, что на вершине - ассоциативен. В данном случае после отъезда умножения остаётся сложение, приоритет которого равен приоритету вычитания, но сложение в отличие от вычитания ассоциативно:
Упражнение №5
Реализовать на python алгоритм сортировочной станции для преобразования произвольных арифметических выражений с 4 действиями (+,-,*,/) из инфиксной записи в обратную польскую.
Упражнение №6(*)
Добавить в предыдущую реализацию поддержку выражений со скобками.