C ++ Exprtk против Python eval ()

Проблема заключается в следующем.
Текстовый файл содержит миллионы строк арифметики — которые требуют быстрой оценки.
Я изучал свои варианты для этой проблемы и написал небольшой скрипт, используя хороший exprtk C++ библиотека.
Код работает и может вычислять выражения, но медленнее, чем я думал. Строки арифметики могут быть довольно длинными, что может усугубить проблему. Из интереса я сравнил время оценки с тем из основного Python eval() Команда и была удивлена, что eval() был в 3-4 раза быстрее, чем exprtk!

Здесь C++ код:

#include <iostream>
#include <fstream>
#include <cstdio>
#include <sstream>
#include <string>

#include "exprtk.hpp"
int main()
{
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
typedef exprtk::parser_error::type error_t;

// Define variables in strings
double A = 1.1;
double B = 2.2;
double C = 3.3;
double m3 = 1.0;
double z3 = 2.0;

symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable("A", A);
symbol_table.add_variable("B", B);
symbol_table.add_variable("C", C);
symbol_table.add_variable("m3", m3);
symbol_table.add_variable("z3", z3);

expression_t expression;
expression.register_symbol_table(symbol_table);

parser_t parser;
// Load the text file and loop over the lines
std::ifstream fin("test.txt");
std::string file_line;
while(std::getline(fin, file_line)) {
// current line of text is in file_line, not including the \n
std::string expression_str = file_line;

if(!parser.compile(expression_str, expression)) {
printf("Error: %s\tExpression: %s\n", parser.error().c_str(), expression_str.c_str());

for(std::size_t i = 0; i < parser.error_count(); ++i) {
const error_t error = parser.get_error(i);
printf("Error: %02d Position: %02d Type: [%s] Msg: %s Expr: %s\n",
static_cast<int>(i),
static_cast<int>(error.token.position),
exprtk::parser_error::to_str(error.mode).c_str(),
error.diagnostic.c_str(),
expression_str.c_str());
}

return 1;
}

double result = expression.value();

printf("%10.16f\n", result);
}
return 0;
}

Вот код Python:

with open("test.txt", 'r') as h:
linesHH = h.readlines()

// Apply list comprehension
matt = [eval(x) for x in linesHH]

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

-10./(A+B)^4-2.500000000000000*A^3/C^3/(A+B)^4-9.250000000000000*A/C/(A+B)^4-2.500000000000000*B^3/C^3/(A+B)^4-9.250000000000000*B/C/(A+B)^4-8.*A^2/C^3/(A+B)^4-8.*B^2/C^3/(A+B)^4-1.750000000000000*A/B/(A+B)^4+2.250000000000000*B^2/C^2/(A+B)^4-1.750000000000000/A*B/(A+B)^4-1./A^2*B^2/(A+B)^4-.2500000000000000/A^3*B^3/(A+B)^4-13.*A/C^2/(A+B)^4-13.*B/C^2/(A+B)^4-.2500000000000000*A^3/B^3/(A+B)^4+2.250000000000000*A^2/C^2/(A+B)^4-1.*A^2/B^2/(A+B)^4+62./C/(A+B)^4*z3-11./C/(A+B)^4-13.*A^2*B/C^3/(A+B)^4+3.500000000000000*A^2/B/C/(A+B)^4-13.*A*B^2/C^3/(A+B)^4+3.500000000000000/A*B^2/C/(A+B)^4-14.*A*B/C^3/(A+B)^4-.5000000000000000/A*B^4/C^3/(A+B)^4-1./A*B^3/C^2/(A+B)^4-.2500000000000000/A^2*B^4/C^2/(A+B)^4-2./A^2*B^3/C/(A+B)^4-.2500000000000000/A^3*B^4/C/(A+B)^4-1.*A^3/B/C^3/(A+B)^4-.5000000000000000*A^3/B^2/C^2/(A+B)^4-2.500000000000000*A^2/B/C^2/(A+B)^4-.5000000000000000*A^2/B^2/C/(A+B)^4-2.*A/B/C/(A+B)^4-1./A*B^3/C^3/(A+B)^4-2.500000000000000/A*B^2/C^2/(A+B)^4-2./A*B/C/(A+B)^4-.5000000000000000/A^2*B^3/C^2/(A+B)^4-.5000000000000000/A^2*B^2/C/(A+B)^4-.5000000000000000*A^4/B/C^3/(A+B)^4-.2500000000000000*A^4/B^2/C^2/(A+B)^4-.2500000000000000*A^4/B^3/C/(A+B)^4-1.*A^3/B/C^2/(A+B)^4-2.*A^3/B^2/C/(A+B)^4-18.*A*B/C^2/(A+B)^4+26.*A/C^2/(A+B)^4*z3+26.*B/C^2/(A+B)^4*z3+11.*A/B/C/(A+B)^4*z3+5./A*B^2/C^2/(A+B)^4*z3+11./A*B/C/(A+B)^4*z3+1/A^2*B^3/C^2/(A+B)^4*z3+5./A^2*B^2/C/(A+B)^4*z3+1/A^3*B^3/C/(A+B)^4*z3+A^3/B^2/C^2/(A+B)^4*z3+A^3/B^3/C/(A+B)^4*z3+5.*A^2/B/C^2/(A+B)^4*z3+5.*A^2/B^2/C/(A+B)^4*z3

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

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

Для ускорения можно использовать алгоритм маневрового двора и нотацию обратной полировки, но только из этого сравнения я был удивлен разницей в скорости между C++ а также Python, Есть ли очевидная причина такой разницы в скорости?
Есть ли намного больше накладных расходов в exprtk или мой код просто полная чушь? Вероятно, последний …

редактировать

Причина, по которой я пошел с библиотекой exprtk, связана с чтением этот математическое исследование парсера

1

Решение

Наивное чтение строк в C ++ намного медленнее, чем Python, как упоминалось в этом сообщение, чтобы получить более быстрые результаты с C ++, используйте один из предложенных методов в упомянутом посте, чтобы ускорить чтение строк

1

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

Других решений пока нет …

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