Pull to refresh

Comments 23

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

Достижение высокой производительности при вычислении математических выражений из строки требует использования современных возможностей .NET и эффективных алгоритмов. Это реализовано в библиотеке MathEvaluator для .NET. В предыдущей статье я описал подход, лежащий в основе

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

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

Время прямого вычисления: 724.03 нс

Время компиляции: 107,224.06 нс

Время выполнения скомпилированной функции: 26.68 нс

Эти данные кажутся мне несколько странными, по моим оценкам время компиляции должно быть примерно сопоставимо с временем прямого вычисления. Поскольку из вашей публикации абсолютно невозможно понять, в какое промежуточное представление вы компилируете выражения (я с ужасом подумал - неужто прямо в команды процессора?), невозможно и оценить ценность вашей библиотеки. Естественно, такого рода библиотека вряд ли может быть совсем новаторской, а бенчмарки совсем не помогают осознанию её преимуществ или хотя бы особенностей

Ноу хау в том что сделано просто, поэтому работает быстро. Я не занимался оверинженирингом. В основе правило приоритета операции, рекурсия, ReadOnlySpan и префиксное дерево для поиска операторов и функциий, нужно объяснять как устроено префиксное дерево? в интернете полно материала по этому поводу. В статье есть ссылка на первую статью где это описано, читайте внимательно. Новаторство в том что я решил задачу как математик, переложив логику в код что позволяет разбирать такие формулы как sin-3/cos1 или -3^4sin(-π/2) без регулярных выражений и сложных архитектур. Это третья статья и здесь я описал именно то что во 2 версии появилась компиляция.

Наиболее быстрый способ компиляции в C# это LambdaExpression.Compile, строю я expression tree по таким же правилам как и рассчитываю, только получаю Expression а не значение. При построении дерева уже не играет роли как быстро я это делаю так как основное время это компиляция этого дерева поэтому не повторял то что я описывал про быстрое вычисление.

строю я expression tree по таким же правилам как и рассчитываю, только получаю Expression а не значение.

Поэтому и кажется странным, что это занимает в 150 раз больше времени

Компиляция требует времени, скомпилированное выражение это как раз и есть IL код

Если воспользуетесь оп-кодами вместо Expression, то сможете выиграть немного времени на построении.

префиксное дерево для поиска операторов и функциий, нужно объяснять как устроено префиксное дерево?

Не совсем понял, при чем тут префиксное дерево? Это структура более сложная, чем двоичное дерево арифметического выражения.

Binary algebraic expression tree equivalent to ((5 + z) / -8) * (4 ^ 2)
Binary algebraic expression tree equivalent to ((5 + z) / -8) * (4 ^ 2)

Такое дерево вы имеете в виду?

Нет я имею ввиду именно префиксное дерево. Картинка по ссылке, можете сравнить

https://en.m.wikipedia.org/wiki/Trie

А какие преимущества у префиксного дерева для вычисления значания выражения?

По сути я использую 2 дерева, первое то что вы прислали "строится" с помощью рекурсии, по сути его физически нет но расчёт идёт от ветвей к корню, префиксное дерево используется для поиска кастомных операторов и функций.

По сути я использую 2 дерева, первое то что вы прислали "строится" с помощью рекурсии, по сути его физически нет но расчёт идёт от ветвей к корню, префиксное дерево используется для поиска кастомных операторов и функций

Если дерева "физически нет" - как вам удаётся организовать многократное вычисление одного и того же выражения? Может, ссылка на двоичное дерево выражения все-таки сохраняется?

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

Вы перепутали компиляцию и evaluation. Скомпилированный делегат повторно не компилируется. Он используется как есть как в примерах в статье fn()

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

Спасибо за бенчи, оценил производительность NCalc :)

Мне на проекте нужно будет многократно вычислять выражения похожие на WHERE часть SQL. Где-то 10млн строк и 100 правил. Каждое правило нужно вычислить на каждой строке.

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

Т.е. как я понимаю вы не пробовали еще ни то ни другое, но выводы делаете только по этой статье, поэтому необходимо пояснить, я не ставил своей целью сделать полное сравнение с NCalc, я сравнивал только скорость работы. Когда я начинал я не ориентировался на NCalc, хотел реализовать свою идею не оглядываясь на другие проекты, вы правы он ходовой, но ориентироваться только на это в выборе тоже не верно. Я поддерживаю всех разработчиков, контребтютером в опен сорс, как я теперь вижу, быть очень тяжело, поддержкии мало от сообщества зато критики вагон и маленькая тележка, нет кого-то лучше или хуже, все идеи имеют место быть, поэтому критиковать NCalc не хотелось бы. Идея MathEvaluator это простота, понятность, скорость и возможность кастомизации через контекст. По поводу других решений я бы прежде чем принимать решения посоветовал обратить внимание не только на "ходовой" или нет, а еще хотя бы на то, сколько там открытых багов, как быстро они закрываются (это к вопросу о поддержке) и сложность архитектуры что может накладывать определенные ограничения на расширерение возможностей этой библиотеки в случае необходимости.

К слову на днях выкачу поддержку комплексных чисел.

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

я не ставил своей целью сделать полное сравнение с NCalc, я сравнивал только скорость работы

И я увидел, что скорость работы сравнимая, за это спасибо. Т.е. скорость пока не является критическим критерием выбора.

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

Лично я вообще никак не критику MathEvaluator, мне нравятся статьи о нём :)

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

Рассуждения такие: NCalc уже больше 10 лет, в нём должны быть исправлены все детские болезни, найдены все более менее критичные баги, для него существует куча материалов. С точки зрения управления разработки - это хорошо. Как ответственный за проект я сначала возьму NCalc и посмотрю на другую библиотеку только NCalc по какой-то причине не сможет.

Опять таки встречно: где гарантии, что завтра MathEvaluator не перестанет поддерживаться и там не останется какого-нибудь неприятного бага?

MathEvaluator это простота, понятность, скорость и возможность кастомизации через контекст

Я просто показал, как рассуждают люди, которым нужна либа. Им без разницы простоту и понятность. Им нужна поддержка, скорость внедрения, отсутствие проблем и документация. Из интересного я вижу только возможность кастомизации. Тут нужно думать не с точки зрения "смотрите какая клёвая либа", а с точки зрения "моя либа позволяет решить такие-то ваши проблемы".

Надеюсь моя обратная связь поможет с позиционированием библиотеки.

Опять таки встречно: где гарантии, что завтра MathEvaluator не перестанет поддерживаться и там не останется какого-нибудь неприятного бага?

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

Sign up to leave a comment.

Articles