Как стать автором
Обновить

Комментарии 25

А как будет выглядеть вычисление 10000 значений по одной и той же формуле с различными значениями переменной (скажем, изменяющимися в каком-то диапазоне), можете привести пример?

Здесь примеры выражений и benchmarks.
Все крутится около 500 ns или 0.5 ms даже примеры с использованием переменных в научном контексте за счет применения структуры префексное дерево в контекте. Зависит от сложности выражений, есть примеры и 300-400 ns.

Все равно не понимаю. Там все примеры - это вычисление одного выражения. Хотел бы понять, как это выглядит в цикле - одно и то же выражение, вычисляемое 10000 раз для различных значений переменной

Судя по коду, нет ни синтаксического дерева ни дерева выражений, т. е. парсинг и вычисление делаются вместе. Выражение не компилируется.

500 ns т.е. 0.0005 ms, сам себе в ногу выстрелил, да вы правы 1ms это 10^6 ns

Вижу есть примеры с параметризацией выражений
var value1 = "ln(1/-x1 + sqrt(1/(x2*x2) + 1))"

.Bind(new { x1, x2, sqrt, ln })

.Evaluate();
в этом случае скомпилированное выражение закэшируется или будет парситься каждый раз?

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

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

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

1000 вычислений это 0.5 ms, соответственно 1 млн это полсекунды

Когда-то давно делал подобную задачу. Еще для Трубо-Паскаля.

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

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

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

Совершенно верно, я тоже дифференцирование реализовал. Еще написал крайне полезную функцию, которая показывает, зависит ли данное выражение в виде дерева от заданной пременной

И еще один аспект - вычисление следует выполнять с помощью выражения, заведомо не содержащего синтаксических ошибок, иначе каждый раз при вычислении придется выполнять кучу проверок

Совершенно верно, я тоже дифференцирование реализовал.

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

Хотя нет, даже производную не всегда легко взять. Например, y = x^x, тут сначала надо привести к e^(x * ln(x))

Еще написал крайне полезную функцию, которая показывает, зависит ли данное выражение в виде дерева от заданной пременной

Формально зависит, или фактически?

Например, f(x) = sin(x)^2 + cos(x)^2 не зависит от х. Это опять же к вопросу упрощений.

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

Это зависит от того, что вы собираетесь с этой производной делать дальше. Мне она нужна была для получения якобиана системы диффуравнений, который далее должен был использоваться в вычислениях. Для этого вполне достаточно было иметь элементы якобиана в виде деревьев, очищенных от вырожденных случаев (x*0=0 и т.п.). Если же подразумевается иное использование (например, студент на экзамене должен доказать, что умеет брать производные) - тогда действительно могут понадобиться дополнительные упрощения

Если нужна производная функции, то её проще через дуальные числа получить. А также через те же дуальные числа можно разрешать неопределённости вида 0/0.

Подобных проектов много. На базе идеи AngouriMath делался калькулятор фишка которого была в том, что расчеты из текстового поля (по типу рабочего листа MatLab) преобразовывались в отчет в ворде с оформленными формулами и, даже, графиками и векторными диаграммами. MathML не стоит использовать, лучше LATEX, из под него проще сделать вычисления выражений. Набрал в текстовом виде задачу, нажал кнопочку и, если расчетами доволен, через несколько секунд готов красивенький вордовский отчет. Поменял исходные данные и следующий вариант готов. Не надо в ворде перебивать формулы и циферки из маткада или вольфрама.

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

Какая разница за 0,1 мкс или 10 мкс вычислится выражение, если его надо 1 минуту набирать?

Скорость парсинга вообще не имеет значения, потому что оно один раз делается. Имеет значение скорость выполнения выражения в виде синтаксического дерева или списка в виде польской записи, а также дополнительная функциональность по преобразованию его в код, latex и т.д. А в таком виде это уровень студенческой работы, так вы донатов не соберёте, уж извините.

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

Это не оскорбление. Я делал подобное именно студентом 2-го курса в качестве курсовой работы, только там сверху ещё скелетная 3D-анимация была.

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

О, да!! Мне тоже очень нужны просчеты булевских выражений, делаю свой ЧПУ постпроцессор))

А что имеется ввиду под "булевскими операциями"?

Простые, чисто булевские, выражения типа "x and y", или микс с математическими, типа "(x>0) and (sin(y)=1)"?

Хотите иметь классическую булеву логику (true/false) или тренарную (true/false/unknown)?

Просто интересно.

Классическую. У меня здоровое выражение, десяток булевских параметров, true|false на выходе, операторы AND, OR, скобки.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории