Подтвердить что ты не робот

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

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

4b9b3361

Ответ 3

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

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

Codepression Expression Evaluator

Ответ 4

Я знаю, что это старо, но я столкнулся с этим, пытаясь разработать калькулятор как часть более крупного приложения и столкнулся с некоторыми проблемами, используя принятый ответ. Ссылки были IMMENSELY полезны в понимании и решении этой проблемы и не должны быть снижены. Я писал приложение для Android на Java и для каждого элемента в выражении "строка" я фактически сохранил String в ArrayList, когда пользователь набирает на клавиатуре. Для преобразования infix-to-postfix я повторял каждую строку в ArrayList, а затем оценивал недавно созданный постфикс ArrayList строк. Это было фантастически для небольшого числа операндов/операторов, но более длинные вычисления были последовательно отключены, особенно когда выражения начали оценивать нецелые числа. В приведенной ссылке для Infix to Postfix conversion" предлагается всплывать стек, если отсканированный элемент является оператором, а элемент topStack имеет более высокий приоритет. Я обнаружил, что это почти правильно. Высказывание элемента topStack, если приоритет выше, или EQUAL для отсканированного оператора, наконец, сделали мои вычисления правильными. Надеюсь, это поможет любому, кто работает над этой проблемой, и благодаря Джастину Полию (и fas?) За предоставление некоторых бесценных ссылок.

Ответ 5

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

Ответ 7

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

Ответ 8

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

Ответ 9

Разработчики всегда хотят иметь чистый подход и попытаться реализовать логику синтаксического анализа с нуля, обычно заканчивая Dijkstra Shunting-Yard Algorithm. Результат - аккуратный код, но, возможно, с ошибками. Я разработал такой API, JMEP, который делает все это, но мне потребовались годы, чтобы иметь стабильный код.

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

Ответ 10

Прошло 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 создан мной.