решатель — Как разобрать строку, начиная с конца Переполнение стека

Добавлен еще один пример.

У меня есть математическое выражение, например, cos (pi * cos (pi * sin (pi * y))), и я хочу его решить.

Я думаю, что лучший способ разобрать это, начиная с конца строки.

Итак, в выражении выше:

  1. я = грех (пи * у)
  2. я = соз (пи * я)
  3. я = соз (пи * я)

Я собираюсь добавить другое выражение в качестве примера:
сов (пи * (ср (х, х) * у))

Это должно быть оценено следующим образом:

  1. я = ср (х, х)
  2. я = я * у
  3. я = соз (пи * я)

Что вы думаете об этом? Не могли бы вы помочь мне реализовать код?

заранее спасибо

2

Решение

У меня есть математическое выражение, например, cos (pi * cos (pi * sin (pi * y)))
и я хочу решить это.

Нет, ты хочешь оценивать Это. Решение говорит вам условия, при которых что-то верно. Оценка просто дает вам итоговую ценность.

Я думаю, что лучший способ разобрать это, начиная с конца строки.

Традиционный способ синтаксического анализа таких выражений — использование рекурсивного спуска. Это более общий и намного легче осуществить. Поток управления выглядит примерно так:

  • cos (

    • где знак равно pi * cos ( В

      • где В знак равно pi * sin ( С

        • где С знак равно pi * y

          Теперь вы можете оценивать pi * yи вернуть значение С

        … и теперь у вас есть С, Вы можете оценить pi * sin(C) и вернуть значение В

      … и теперь у вас есть значение В, Вы можете оценить pi * cos(B), возвращая значение как

    … и теперь у вас есть значение , Вы можете оценить cos(A), и вы сделали.

Это именно так, как выражение C cos(M_PI * cos(M_PI * sin(M_PI * y))) работает (предполагая общую, но нестандартную постоянную для π).

это оценивали примерно справа налево (на самом деле изнутри наружу), но все же читать слева направо. Мы только что отметили временные значения для ясности.

Этот поток управления часто просто превращается в дерево

[cos of _]
|
[pi * _]
|
[cos of _]
|
[pi * _]
|
[sin of _]
|
[pi * y]

Но очевидно, что вы можете просто оценить результат один раз, если вам не нужно сохранить дерево на потом. (Обратите внимание, что это одностороннее дерево по-прежнему является деревом, оно просто вырождено из-за того, как ваше выражение вложено).

…Что вы думаете об этом?

Проблема с вашим решением заключается в том, что оно разбивается на разные структуры вложенности, например.

cos( sin((pi * x) + y) + sin(y + (pi * x)) )

нельзя просто оценить справа налево.

Не могли бы вы помочь мне реализовать код?

Отделите обработку строк (токенизацию) от анализа и оценки. Намного легче рассуждать независимо от вашей обработки строки и вашей математики.

3

Другие решения

Редакция: Улучшение базового варианта.

Это просто псевдокод, но идея должна работать:

int ParseAndCalculate(string input)
{
if (input.DoesConvertToSomeIntegerWork())
return input.ConvertToSomeInteger();

string actionRequired = GetActionFromString(input, "(");
int tempIndex = input.LocationOfFirst("(");
int tempResult = ParseAndCalculate(input, tempIndex, input.Length -1);
tempResult = PerformRequiredAction(tempResult, actionRequired);

return tempResult;
}

Не уверен, что вы должны вернуть в базовом случае. Может быть, выяснить, какая там реальная стоимость?

0

Если вы хотите написать программу на C / C ++, которая может анализировать математические выражения, как указано выше, вы можете написать нисходящий анализатор на C / C ++ самостоятельно, или вы можете захотеть взглянуть на GNU Bison.

Бизон является генератором парсера, и это происходит с пример это довольно близко к вашей проблеме.

Преимущества его использования состоят в том, что вам не нужно заботиться о реальных процедурах синтаксического анализа самостоятельно, но вы можете сосредоточиться на спецификации грамматики и обратных вызовах математических функций. Я должен признать, что попасть в Bison и интегрировать его в сборку может быть довольно сложно. Я не могу сказать, действительно ли это полезно в вашей ситуации, но по крайней мере это надежный и надежный инструмент, используемый для решения таких задач.

Его также можно использовать для вычисления выражений в «правильном» порядке, поскольку он поддерживает определения приоритетов операторов.

0
По вопросам рекламы [email protected]