2017-07-21 88 views
1

問題如下。
一個文本文件包含數百萬行算術 - 需要快速評估。
我一直在探索我的這個問題的選項,並使用漂亮的exprtkC++庫編寫了一個小腳本。
該代碼起作用並能夠評估表達式,但速度比我想象的要慢。算術線可能會變得很長,這可能會加劇這個問題。出於興趣,我將評估時間與基本Python eval()命令的評估時間進行了比較,並驚訝於eval()比exprtk快3-4倍!C++ Exprtk vs Python eval()

這裏是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圖書館去的原因是由於閱讀this數學解析器板凳標記調查。

+0

你啓用優化編譯? –

+0

@BenSteffan我使用-O2編譯器標誌編譯。 – Yeti

+1

Python中的'^'是異或。此外,您的計時可能比磁盤訪問更多地表達解析。 – user2357112

回答

1

在C++天真地念臺詞是比Python慢​​得多如本post提到,要獲得使用C更快的結果++中使用的建議方法之一,在提到後加快讀取線