Создать объект который вычисляет значение целочисленного арифметического выражения

от admin

Создать объект который вычисляет значение целочисленного арифметического выражения

B правой части каждого сообщения есть стрелки ⇧ и ⇩ . Не стесняйтесь оценивать ответы. Чтобы автору вопроса закрыть свой тикет, надо выбрать лучший ответ. Просто нажмите значок ✔ в правой части сообщения.

Бесплатный курс по пентесту от Школы Кодебай

Запишись на вводный видеокурс по пентесту , состоящий из 24 уроков. Разные инструменты, тактики и навыки: сканирование сети, фаззинг, брутфорс, сниффинг, sql-инъекции, mimikatz, загрузка полезной нагрузки, эксплуатация разных уязвимостей, XSS, CSRF и немного Reverse-shell. Будет полезен для быстрой подготовки к CTF, а так же для прохождения курсов « SQL Injection Master » и « WAPT ».

Бесплатный курс SQL Injection от Школы Кодебай

Запишись на вводный курс по SQL инъекциям. Курс состоит из 6 видео уроков. К каждому уроку приложена методичка. Есть общий чат для учащихся. Будет полезен для быстрой подготовки к CTF, а так же для прохождения курсов « SQL Injection Master » и « WAPT ».

Создать объект который вычисляет значение целочисленного арифметического выражения

and end nil shr

asm file not string

array for object then

begin function of to

case goto or type

const if packed unit

constructor implementation procedure until

destructor in program uses

div inline record var

do interface repeat while

downto label set with

else mod shl xor

pi- число

const n=5; k=-43; a=1.65; b=-6E3;

var x1, x2,u,v: real;

J, f1, t: integer;

(a+b)/(a-b)

sqrt(abs(a-b))

a0+a1*x+a2*sqr(x)+a3*x*sqr(x)

В более общем случае, когда в выражении a b — показатель, и – вещественное число, можно использовать логарифмическое тождество: a b =e b * ln ( a ) и имеющиеся в языке Паскаль стандартные функции expи ln. При этом следует помнить, что логарифмическая функция определена только для положительных аргументов. Например, арифметическое выражение на языке Паскаль можно записать следующим образом:

read(a, b, c, d)

var T : real;

read (T, J, K) ;

253.98 100 G[Enter]

var A, B : integer ;

read ( A, B ) ;

read ( C, D ) ;

18758 34 [Enter] 2.62E-02 1.54E+01 [Enter].

2. 62E−02 1.54E+01 [Enter]

write( X, Summa, Arg1, Arg2) ;

Пример.

Алгоритм вычисления арифметического выражения в виде строки

В нашей славной компании есть очень хорошая, стимулирующая система т.н. грейдов: раз в полгода, любой разработчик может повысить свой грейд, что влечет за собой увеличение зарплаты. Другими словами, грейд — это аттестация. Хочешь увеличить зарплату? Раз в полгода можешь аттестоваться на следующую ступень, и расти от джуна до сеньора (за один раз можно перепрыгнуть не более, чем на две ступени). Аттестация проходит в дружелюбной форме, вопросы выложены в базе знаний, никакой бюрократической волокиты нет. Условием для допуска к аттестации служит решение алгоритмической задачи.

И вот я аттестовываюсь, и мне дают задачу: вычислить арифметическое выражение в виде строки. Да фигня вопрос, скажете вы (как и я в начале). Все это давно описано, и ничего сложного здесь нет. Вы будете одновременно правы и неправы. Вопрос то, конечно фигня, но это алгоритмическая задача. Готовые библиотеки использовать нельзя, нужно написать именно алгоритмическое решение. И окунулся я в мир операндов, операторов, как бинарных, так и унарных. И как все это красиво распарсить, как не запутаться со скобками, и… самым коварным оказался унарный минус.

Решение писать будем на php.

Чего-то нового в этой задаче, конечно же, нет. После недолгого гугления мы находим, что для разбора арифметического выражения в виде строки, машиной, лучше всего подходит Обратная польская запись. Материалов по ОПЗ много, разбирать её подробно смысла нет. Например, ссылка на вики.

Пример записи в ОПЗ: 3 4 2 + *

В упрощенном виде можно сказать, что ОПЗ — это запись арифметического выражения, в котором операторы записываются после операндов, и в котором нет скобок.
Под операндами мы понимаем вещественные числа, под операторами — символы арифметических операций +, -, *, /, ^

Почему ОПЗ так хороша для машинных вычислений?

Да потому, что в выражении нет скобок, и машине не надо производить лишних действий. Есть только операнды и операторы. Причем операторы всегда пишутся после операндов (постфиксная запись).
Машина линейно идет по строке, если попалось число, то кладем его в стек, иначе, если оператор бинарный, берем из стека правый операнд, берем из стека левый операнд, вычисленное значение кладем в стек. Когда дойдем до конца строки, достаем из стека результат вычислений.

В упрощенном виде (без проверок) это выглядит так:

Все вроде просто, понятно, пока мы не продолжим читать про ОПЗ дальше. Цитата из вики:

Т.е. знак — (минус) мы можем использовать только как оператор вычитания. Для обозначения унарного минуса в ОПЗ, мы его использовать не можем.
Нам прямо предписывается использовать для обозначения унарного минуса любой свой придуманный символ. Давайте договоримся, что это будет тильда

.
Более того — унарный оператор в ОПЗ имеет наивысший приоритет (в данной статье мы будем говорить про унарный минус)!

Что за нафиг? Почему какому-то несчастному оператору (унарный минус), уделяется столько внимания? Мы должны придумать для него специальный символ, и вдобавок ко всему у него еще и наивысший приоритет при разборе выражения?

Ну, с приоритетом понятно — действительно, прежде чем вычислять выражение, мы, в первую очередь, должны разобраться с положительными и отрицательными числами.

Разбираемся дальше. Для этого примем (вспомним) два постулата:

  1. Любое число, в памяти машины, хранится в виде байт-кода. Отрицательное число определяется значением старшего бита
  2. Для машины символ минус — это всегда оператор вычитания. Ни о каких унарных минусах машина не знает

Что из этого следует? Давайте рассмотрим простейший пример:
$a = -2
Что происходит в данном примере, с точки зрения машины?
Переменной $a необходимо присвоить отрицательное значение числа 2.
Для машины минус — это оператор вычитания. Операция бинарная. Справа 2, а слева ничего нет. Т.е. слева 0.
Т.е. в $a попадет результат вычисления выражения 0 — 2 . Вычитать машина умеет прекрасно, в память машины будет записано верное отрицательное число.

Смотрим дальше. Есть выражение с двумя унарными минусами, например —2 .
Как его должна считать машина? Если следовать нашей логике, то так: 0 — (0 — 2) .
Т.е. унарный минус — это не просто вычитание операнда из ноля, но еще и правоассоциативная арифметическая операция, как и оператор возведения в степень.

Читать:
Как установить кодек hevc windows 10

Прежде чем идти дальше, давайте дадим определение унарному минусу в инфиксном арифметическом выражении:

  • Унарный минус — это оператор — (минус), перед которым в арифметическом выражении всегда стоит не число, и не закрывающая скобка
Подведем промежуточные итоги
  1. Мы выяснили, что для машинного разбора строки с арифметическим выражением необходимо его привести к ОПЗ (постфиксная запись)
  2. Мы разобрались почему у унарного минуса наивысший приоритет, и мы запомнили, что у него должен быть свой символ (у нас это тильда
Нам осталось разобрать алгоритм приведения инфиксного арифметического выражения к постфиксному

Опять же всё давно изобретено до нас, использовать мы будет классический алгоритм сортировочной станции. Просто распишем его максимально подробно и понятно.

Прежде чем приступить к описанию алгоритма уточним давно известный алгоритм приоритета стековых операций.

В нашем случае операторы и приоритеты стековых операций будут выглядеть так:

Также необходимо определить правоассоциативные арифметические операции:

В процессе разбора строки мы будем использовать понятие выходная строка (постфиксное выражение) и стек.

Алгоритм приведения инфиксной записи к постфиксной

Если при разборе строки нам встретилось число, то помещаем его в выходную строку

Иначе

Если в стеке пусто, или нам попалась открывающая скобка — помещаем оператор в стек

Если нам попался правоассоциативный оператор, и на вершине стека лежит такой же оператор, то ничего не делаем, просто добавляем оператор в стек

Иначе

  • Если нам попалась не закрывающая скобка, то выталкиваем из стека, в выходную строку, операторы с бОльшим, или равным приоритетом. Если, при выталкивании из стека, нам попался оператор с мЕньшим приоритетом — останавливаемся.
    Добавляем оператор на вершину стека.
  • Если нам попалась закрывающая скобка, то выталкиваем из стека, в выходную строку, все операторы до первой открывающей скобки. Открывающую скобку из стека удаляем
  • Если строка закончилась — выталкиваем все операторы из стека в строку вывода

Собственно всё. Данный алгоритм можно реализовать на любом ЯП.

Давайте приведём «вручную» выражение 2 * (2 + -2 ^ 2 ^ 3) — 1 к ОПЗ, и вычислим его

Приводим к постфиксной записи

Определим переменные для вычисления

Разбираем строку 2 * (2 + -2 ^ 2 ^ 3) — 1

Первый символ в строке 2, это число — помещаем его в выходную строку

Следующий символ — это оператор * — помещаем его в стек

Следующий символ — это оператор ( — помещаем его в стек

Следующий символ — это число 2 — помещаем его в выходную строку

Следующий символ — это оператор + — помещаем его в стек

Следующий символ — это оператор унарный минус

— помещаем его в стек

Следующий символ — это число 2 — помещаем его в выходную строку

Следующий символ — это оператор ^ — выталкиваем из стека унарный минус, помещаем ^ в стек

И так далее… — если число, то помещаем в строку вывода, если оператор, то пытаемся вытолкнуть из стека, в строку вывода, другие операторы, сам оператор ставим на вершину стека. Всё согласно алгоритму выше.
Открывающая скобка имеет наименьший приоритет, её вытолкнуть нельзя, она должна быть уничтожена закрывающей скобкой. Приоритеты операторов мы также определили.

В конечном итоге мы получаем постфиксное выражение 2 2 2

Ну, дальше, как было написано выше, дело техники.

  • Мы идем по строке с постфиксным выражением.
  • Если нам попалось число, то кладём его в стек.
  • Если нам попался унарный минус, то приводим число на вершине стека, к отрицательному значению (0 минус операнд).

Если нам попался бинарный оператор

  • берем с вершины стека число — это правый операнд
  • берем с вершины стека число — это левый операнд
  • вычисляем выражение, кладем его в стек

Если строка закончилась, возвращаем вычисленное значение из стека (если арифметическое выражение верно, то в стеке останется один элемент).

Полное решение на языке php

Пример использования класса Calculate

Листинг класса Calculate

Подведем итоги

Для красивого вычисления арифметического выражения в виде строки необходимо:

  1. Разобраться что такое Обратная польская запись, и почему она идеально подходит для машинных вычислений
  2. Привести арифметическое выражение к ОПЗ, и вычислить его

И для первого, и для второго пункта ключевым понятием является стек — последовательность, организованная по принципу — последний зашел, первый вышел. На вершине стека всегда находится его последний элемент.

Пример 4.3.4-4.Вычислить значения арифметических выражений и вывести на экран результаты вычислений.

Выполним запись арифметических выражений на языке vb:

Программный код показан на рис. 4.3.4-10.

Option Strict On

Option Explicit On

Imports System.Math

Public Class Form1

Sub Pr348(ByVal x As Single,ByVal a As Single,ByVal b As Single,_

ByVal t As Single, ByRef y As Single, ByRef z As Single)

y = CSng(9 * x ^ 2 + Sin(x) * Sin(x) * Sqrt(a + b))

z = CSng((Sqrt(x^t))^(1 / 3) * (a * x ^ 3 — (x * x) / (1/2)))

Private Sub Button1_Click(sender As Object, e As EventArgs) _

Handles Button1.Click

Dim a, b, x, t, z, y As Single

a = CSng(Val(TextBox1.Text)) : b = CSng(Val(TextBox2.Text))

x = CSng(Val(TextBox4.3.Text)) : t = CSng(Val(TextBox4.Text))

Pr344(x, a, b, t, y, z)

TextBox5.Text = Str(y)

TextBox6.Text = Str(z)

Рис. 4.3.4-10. Программный код Пример 3.4-4

Результат программы представлен на рис. 4.3.4-11.

Рис. 4.3.4-11. Результат программы Пример 3.4-4

Выполнить ту же задачу с использованием функций InputBox()иMsgBox( )(Рис. 4.3.4-12).

Option Strict On

Option Explicit On

Imports System.Math

Public Class Form1

Sub Pr3410(ByVal x As Single,ByVal a As Single, _

ByVal b As Single, ByVal t As Single, _

ByRef y As Single, ByRef z As Single)

y = CSng(9 * x ^ 2 + Sin(x) * Sin(x) * Sqrt(a + b))

z = CSng((Sqrt(x^t))^(1 / 3) * (a * x^3 — (x * x) / (1 * 2)))

Private Sub Button1_Click(sender As Object, e As EventArgs) _

Handles Button1.Click

Dim a, b, x, t, z, y As Single

a = CSng(InputBox(«Введите значение А», «Ввод 1 числа»))

b = CSng(InputBox(«Введите значение В», «Ввод 2 числа»))

x = CSng(InputBox(«Введите значение X», «Ввод 3 числа»))

t = CSng(InputBox(«Введите значение T», «Ввод 4 числа»))

Pr3410(x, a, b, t, y, z)

MsgBox(«Значение Y Получаем ответ»)

MsgBox(«Значение Z Получаем ответ»)

Рис.4.3.4-12. Программный код Вычисления арифметических выражений использованием функций InputBox() иMsgBox( )

Результаты работы программы представлены на рис. 4.3.4-113, 4.3.4-14.

Рис. 4.3.4-13 Вывод значения Y Рис. 4.3.4-14. Полученное значение Z

Пример 4.3.4-5. Найти ёмкость конденсатора с, если известны: площадь пластин s и расстояние между ними L. Следует учесть, что в конденсатор вставлена пластина толщиной d, параллельная его обкладкам.

С – емкость конденсатора.

E0 – электрическая постоянная = 8,85 . 10 -12

Похожие статьи