Умный дизайн математического парсера?

Как лучше всего разработать математический синтаксический анализатор? Я имею в виду функцию, которая принимает математическую строку (например: «2 + 3/2 + (2 * 5)») и возвращает вычисленное значение? Я написал один на VB6 много лет назад, но в итоге он стал раздутым и не очень портативным (или умным в этом отношении ...). Приветствуются общие идеи, псевдокод или реальный код.


person Community    schedule 22.09.2008    source источник
comment
вы можете проверить реализацию java алгоритма маневровой станции здесь: projects.congrace.de/exp4j   -  person fasseg    schedule 15.11.2011
comment
Ознакомьтесь с кодом, который я разместил в https://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence/46722767#46722767   -  person user4617883    schedule 15.10.2017


Ответы (10)


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

person Justin Poliey    schedule 22.09.2008
comment
Я не думаю, что алгоритм маневровой станции может справиться с правильной привязкой унарного минуса к основанию экспонент. т.е. он не может анализировать -2 ^ 3 как - (2 ^ 3), только как (-2) ^ 3. Хотя я могу ошибаться, я точно не знаю. - person chbaker0; 31.08.2014
comment
@mebob Мне это кажется ошибкой ввода пользователя. Я бы не стал это поправлять. Если бы я чувствовал себя хорошо, я мог бы добавить что-нибудь, чтобы проверить это и предупредить пользователя, что он может ошибаться. - person Yay295; 03.12.2014

Я написал несколько сообщений в блоге о разработке математического парсера. Существует общее введение, базовые знания о грамматики, пример реализации, написанной на Ruby и набор тестов. Возможно, вы найдете эти материалы полезными.

person Community    schedule 22.11.2008

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

В качестве альтернативы вы можете создать реальный синтаксический анализатор и сгенерировать небольшое дерево синтаксического анализа, которое затем будет использоваться для оценки выражения. Опять же, это довольно просто для основных выражений. Обратите внимание на codeplex, так как я считаю, что у них есть математический анализатор. Или просто найдите BNF, который будет включать примеры. Любой веб-сайт, на котором представлены концепции компилятора, будет включать это в качестве основного примера.

Средство оценки выражений Codeplex

person Phil Wright    schedule 22.09.2008

Если у вас есть приложение, работающее постоянно, просто отправьте математическую строку в Google и проанализируйте результат. Простой способ, но не уверен, что это то, что вам нужно, но в каком-то смысле умный.

person JRoppert    schedule 22.09.2008
comment
Я имею в виду, что вы достаточно умны, чтобы знать, как добиться цели ;-) - person JRoppert; 12.12.2008

Я знаю, что это старый, но я столкнулся с этим, пытаясь разработать калькулятор как часть более крупного приложения, и столкнулся с некоторыми проблемами, используя принятый ответ. Ссылки были ОЧЕНЬ полезны для понимания и решения этой проблемы, и их нельзя сбрасывать со счетов. Я писал приложение для Android на Java, и для каждого элемента в выражении «строка» я фактически сохранял строку в ArrayList, когда пользователь вводит на клавиатуре. Для преобразования инфиксного в постфиксный я перебрал каждую строку в ArrayList, а затем оценил вновь упорядоченный постфиксный ArrayList of Strings. Это было фантастически для небольшого количества операндов / операторов, но более длительные вычисления постоянно отключались, особенно когда выражения начали оцениваться как нецелые числа. В предоставленной ссылке для преобразования Infix в Postfix предлагается всплывающее окно Stack, если отсканированный элемент является оператором, а элемент topStack имеет более высокий приоритет. Я обнаружил, что это почти правильно. Выталкивание элемента topStack, если его приоритет выше ИЛИ РАВНО сканированному оператору, наконец, сделал мои вычисления правильными. Надеюсь, это поможет любому, кто работает над этой проблемой, и спасибо Джастину Поли (и Фасу?) За предоставленные бесценные ссылки.

person MarmotXing    schedule 26.04.2014

Связанный вопрос Анализатор уравнения (выражения) с приоритетом? содержит полезную информацию о том, как начните с этого тоже.

-Адам

person Adam Davis    schedule 22.09.2008

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

person Sam Erwin    schedule 22.09.2008

ANTLR - очень хороший генератор парсеров LL (*). Я очень рекомендую это.

person duffymo    schedule 31.12.2008

Разработчики всегда хотят иметь чистый подход и пытаются реализовать логику синтаксического анализа с нуля, обычно заканчивая Алгоритм маневровой верфи Дейкстры. Результат - аккуратно выглядящий код, но, возможно, с ошибками. Я разработал такой API, JMEP, который делает все это, но мне потребовались годы, чтобы иметь стабильный код.

Даже после всей этой работы вы можете увидеть даже на этой странице проекта, что я серьезно подумываю о переходе на использование JavaCC или ANTLR, даже после того, как вся эта работа уже сделана.

person YoYo    schedule 31.08.2014

Через 11 лет после того, как был задан этот вопрос: если вы не хотите заново изобретать колесо, существует множество экзотических математических синтаксических анализаторов.

Есть один, который я написал много лет назад, который поддерживает арифметические операции, решение уравнений, дифференциальное исчисление, интегральное исчисление, базовую статистику, определение функций / формул, построение графиков и т. Д.

Он называется ParserNG и является бесплатным.

Вычислить выражение так же просто, как:

    MathExpression expr = new MathExpression("(34+32)-44/(8+9(3+2))-22"); 
    System.out.println("result: " + expr.solve());

    result: 43.16981132075472

Или используя переменные и вычисляя простые выражения:

 MathExpression expr = new MathExpression("r=3;P=2*pi*r;"); 
System.out.println("result: " + expr.getValue("P"));

Или используя функции:

MathExpression expr = new MathExpression("f(x)=39*sin(x^2)+x^3*cos(x);f(3)"); 
System.out.println("result: " + expr.solve());

result: -10.65717648378352

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

MathExpression expr = new MathExpression("f(x)=x^3*ln(x); diff(f,3,1)"); 
System.out.println("result: " + expr.solve());

 result: 38.66253179403897

Что отличает x^3 * ln(x) один раз при x = 3. Количество раз, которое вы можете отличить, на данный момент равно 1.

или для численного интегрирования:

MathExpression expr = new MathExpression("f(x)=2*x; intg(f,1,3)"); 
System.out.println("result: " + expr.solve());

result: 7.999999999998261... approx: 8

Этот парсер прилично быстр и имеет много других функций.

Завершена работа по переносу его на Swift через привязку к Objective C, и мы использовали его в графических приложениях среди других итеративных вариантов использования.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ. Автором ParserNG является я.

person gbenroscience    schedule 25.04.2019
comment
Какие преимущества у этого есть перед NCalc? github.com/ncalc/ncalc - person intrepidis; 22.02.2021
comment
Вам нужно будет просмотреть документацию к обоим, чтобы увидеть, какой из них имеет больше функций и, особенно, что вам нужно. Однако я говорю о ParserNG, и он имеет много функций, возможно, в будущем. Помимо вычисления выражений, он работает с созданием переменных, созданием функций, решением уравнений, матричными и статистическими функциями, дифференциальным и интегральным исчислением среди прочего. - person gbenroscience; 22.02.2021