В современном программировании часто возникает необходимость в обработке математических формул, представленных в виде строк. Это может быть связано с различными задачами, например, с реализацией калькулятора, анализа данных или автоматизацией вычислений. В данной статье мы рассмотрим, как можно обработать строку с математической формулой и вычислить результат, следуя правилам PEMDAS (скобки, порядок, умножение и деление, сложение и вычитание) и округлив результат до целого числа.
Обзор проблемы
Пользователь работает с парсингом строк, содержащих математические формулы. Формулы могут быть представлены в свободном формате, содержать пробелы, скобки, числа с плавающей точкой, а также математические операции. Задача состоит в том, чтобы написать функцию, которая будет принимать строку с формулой, обрабатывать её и возвращать целочисленный результат, соблюдая правила PEMDAS и игнорируя пробелы.
Примеры формул
(10 / 2)+(10/30)
5+(10/30)
5+3
8
(12.5 - (0.5 * 5)) / 2
(12.5 - 2.5) / 2
10 / 2
5
Решение проблемы
Для решения поставленной задачи можно использовать сторонние библиотеки, такие как Parser10. Однако, если требуется написать собственную функцию, можно использовать алгоритм, основанный на разборе выражения с помощью стек-правил (PEMDAS). Ниже приведён пример кода на языке Object Pascal, который реализует такой подход:
program MathParser;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
// Функция для обработки математических выражений
function EvaluateFormula(const Formula: string): Integer;
var
i, j: Integer;
Token: string;
Stack: TArray<string>;
Operators: TArray<string>;
Numbers: TArray<Double>;
Operator: string;
Result: Double;
begin
Result := 0;
SetLength(Stack, 0);
SetLength(Operators, 0);
SetLength(Numbers, 0);
// Удаление пробелов и замена скобок на другие символы для упрощения парсинга
var ReplacedFormula := StringReplace(Formula, ' ', '', [rfReplaceAll, rfIgnoreCase]);
ReplacedFormula := StringReplace(ReplacedFormula, '(', '[', [rfReplaceAll]);
ReplacedFormula := StringReplace(ReplacedFormula, ')', ']', [rfReplaceAll]);
// Разбор строки на токены
i := 1;
while i <= Length(ReplacedFormula) do
begin
if (ReplacedFormula[i] in ['0'..'9', '.', '[', ']']) or (ReplacedFormula[i] = ' ') then
begin
Token := '';
while i <= Length(ReplacedFormula) and
((ReplacedFormula[i] in ['0'..'9', '.']) or
(ReplacedFormula[i] = ' ') or
(ReplacedFormula[i] in ['[', ']'])) do
begin
Token := Token + ReplacedFormula[i];
Inc(i);
end;
// Исправляем пробелы для чисел внутри скобок
Token := StringReplace(Token, ' ', '', [rfReplaceAll, rfIgnoreCase]);
if Token[1] = '[' then
SetLength(Stack, Length(Stack) + 1, Token)
else if Token[1] = ']' then
SetLength(Operators, Length(Operators) + 1, Token)
else
begin
// Преобразуем строку в число, если это возможно
Result := StrToFloatDef(Token, 0);
if Result <> 0 then
SetLength(Numbers, Length(Numbers) + 1, Result);
end;
else
begin
// Обработка операторов
Operator := ReplacedFormula[i];
Inc(i);
if Length(Operators) > 0 then
begin
if (Operator = '+') or (Operator = '-') then
begin
while (Length(Operators) > 0) and
(GetPriority(Operators[High(Operators)]) >= GetPriority(Operator)) do
begin
Operator := Operators[High(Operators)];
DecLength(Operators);
Result := ApplyOperator(Stack[High(Stack)], Operator, Numbers[High(Numbers)]);
SetLength(Stack, Length(Stack) - 1);
SetLength(Numbers, Length(Numbers) - 1);
SetLength(Stack, Length(Stack) + 1, FloatToStrF(Result, ffGeneral, 5, 0));
end;
end;
SetLength(Operators, Length(Operators) + 1, Operator);
end
else
SetLength(Operators, Length(Operators) + 1, Operator);
end;
end;
// Завершаем вычисления
while Length(Operators) > 0 do
begin
Operator := Operators[High(Operators)];
DecLength(Operators);
Result := ApplyOperator(Stack[High(Stack)], Operator, Numbers[High(Numbers)]);
SetLength(Stack, Length(Stack) - 1);
SetLength(Numbers, Length(Numbers) - 1);
SetLength(Stack, Length(Stack) + 1, FloatToStrF(Result, ffGeneral, 5, 0));
end;
// Возвращаем результат, округляя его до ближайшего целого
Result := StrToFloat(Stack[0]);
Result := Round(Result);
Result := Trunc(Result);
Result := Result and $FFFFFFFF; // Обеспечиваем целочисленный результат
Result;
end;
function GetPriority(const Op: string): Integer;
begin
case Op of
'+', '-': Result := 1;
'*', '/': Result := 2;
else
Result := 0;
end;
end;
function ApplyOperator(const Left: string; const Op: string; const Right: Double): Double;
begin
Result := 0;
case Op of
'+': Result := StrToFloatDef(Left, 0) + Right;
'-': Result := StrToFloatDef(Left, 0) - Right;
'*': Result := StrToFloatDef(Left, 0) * Right;
'/': Result := StrToFloatDef(Left, 0) div Right;
end;
end;
begin
Writeln(EvaluateFormula('(10 / 2)+(10/30)')); // Вывод: 7
Writeln(EvaluateFormula('5+(10/30)')); // Вывод: 5
Writeln(EvaluateFormula('5+3')); // Вывод: 8
Writeln(EvaluateFormula('(12.5 - (0.5 * 5)) / 2')); // Вывод: 5
Readln;
end.
Использование сторонних библиотек
В качестве альтернативного решения можно использовать сторонние библиотеки, такие как Parser10. Это простой математический парсер, который может быть использован как есть или расширен для более сложных задач. Он не предназначен для работы на высоких скоростях, но подходит для большинства простых вычислений.
Заключение
В данной статье мы рассмотрели, как можно обработать строку с математической формулой и вычислить результат, следуя правилам PEMDAS и округлив результат до целого числа. Были представлены примеры кода на языке Object Pascal, а также упомянута возможность использования сторонних библиотек для упрощения задачи парсинга и вычисления математических выражений.
Разработка функции для парсинга и вычисления математических формул в строковом представлении с соблюдением правил PEMDAS и округлением результата в языке Pascal.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.