2011-04-29 474 views
18

可能重複:
Fastest way to read numerical values from text file in C++ (double in this case)C++ stringstream太慢了,怎麼加快?

#include <ctime> 
#include <cstdlib> 
#include <string> 
#include <sstream> 
#include <iostream> 
#include <limits> 

using namespace std; 

static const double NAN_D = numeric_limits<double>::quiet_NaN(); 

void die(const char *msg, const char *info) 
{ 
    cerr << "** error: " << msg << " \"" << info << '\"'; 
    exit(1); 
} 

double str2dou1(const string &str) 
{ 
    if (str.empty() || str[0]=='?') return NAN_D; 
    const char *c_str = str.c_str(); 
    char *err; 
    double x = strtod(c_str, &err); 
    if (*err != 0) die("unrecognized numeric data", c_str); 
    return x; 
} 

static istringstream string_to_type_stream; 

double str2dou2(const string &str) 
{ 
    if (str.empty() || str[0]=='?') return NAN_D; 
    string_to_type_stream.clear(); 
    string_to_type_stream.str(str); 
    double x = 0.0; 
    if ((string_to_type_stream >> x).fail()) 
     die("unrecognized numeric data", str.c_str()); 
    return x; 
} 

int main() 
{ 
    string str("12345.6789"); 

    clock_t tStart, tEnd; 

    cout << "strtod: "; 
    tStart=clock(); 

    for (int i=0; i<1000000; ++i) 
     double x = str2dou1(str); 

    tEnd=clock(); 
    cout << tEnd-tStart << endl; 

    cout << "sstream: "; 
    tStart=clock(); 

    for (int i=0; i<1000000; ++i) 
     double x = str2dou2(str); 

    tEnd=clock(); 
    cout << tEnd-tStart << endl; 

    return 0; 
} 

的strtod:405
sstream:1389

更新:刪除undersocres,ENV:WIN7 + VC10

+0

嘗試使用boost :: spirit代替。 – W55tKQbuRu28Q4xv 2011-04-29 10:30:28

+1

這些雙下劃線名稱在用戶編寫的代碼中是非法的。如果stringstream對你來說太慢 - 你有答案 - 使用strtod。 stringstreams主要是爲了方便和類型安全,而不是速度。 – 2011-04-29 10:47:29

+0

流將收集輸入,然後最終調用strtold進行轉換。讓它很難變得更快! – 2011-04-29 11:00:03

回答

1

HAV你考慮使用lexical_cast從提升?

http://www.boost.org/doc/libs/1_46_1/libs/conversion/lexical_cast.htm

編輯:順便說一句,在clear()應該是多餘的。

+0

謝謝,但我認爲STL的目的不是要慢 – hjbreg 2011-04-29 10:31:30

+1

+1'lexical_cast'但因爲它是使用下面的字符串流,它不會更快。 – 2011-04-29 10:33:07

+0

http://translate.google.com/translate?js=n&prev=_t&hl=en&ie=UTF-8&layout=2&eotf=1&sl=auto&tl=en&u=http%3A%2F%2Fsergey-miryanov.blogspot.com%2F2008%2F06 %2Fblog-post.html – W55tKQbuRu28Q4xv 2011-04-29 10:34:33

2

在一般情況下,如果你需要的速度,考慮這個庫:

http://www.fastformat.org/

(我不知道它是否包含函數轉換字符串或流於其他類型的,雖然如此,也可以不回答你當前的例子)。

有記錄,請注意你在這裏比較蘋果和橘子。 strtod()是一個簡單的函數,具有單一用途(將字符串轉換爲double),而stringstream是一種更爲複雜的格式化機制,它遠遠沒有針對特定目的進行優化。比較公平的比較是比較stringstream和sprintf/sscanf函數,它比strtod()慢,但比stringstream更快。我不確定是什麼讓stringstream的設計比sprintf/sscanf慢,但似乎是這樣。

+0

爲什麼STL比fastformat – hjbreg 2011-04-29 10:33:22

+5

@hjbreg慢,因爲它必須支持語言環境。 – 2011-04-29 10:34:35

+0

@hjbreg:這有幾個原因。其中一部分可能與流設計考慮和未優化實施有關。另一個原因是STL的靈活性,這可能包括語言環境支持和對IO操縱器的支持(我不確定fastformat是否具有這些或某些相同的東西)。 – 2011-04-29 10:41:35

3

字符串流慢。非常慢。如果您正在編寫對大數據集起作用的任何性能嚴重的性能(例如在遊戲過程中更改級別後加載資產),請不要使用字符串流。我建議使用舊式的C語言庫解析函數來表現,儘管我不能說它們與鼓舞精神相比如何。

但是,與c庫函數相比,字符串流非常優雅,可讀且可靠,所以如果您所做的不是性能ciritcal,我建議堅持使用流。

8

C/C++文本到數字格式化非常慢。數據流速度非常緩慢,但即使C數解析速度也很慢,因爲很難將其精確到最後一個精度位。

在生產應用中,閱讀速度很重要,已知數據最多有三位小數,而且沒有科學記數法,我通過手動編寫一個只處理符號,整數部分和任意數字的浮動解析函數,小數位數(「很大」我的意思是比strtod快10倍)。

如果你不需要指數並且這個函數的精度足夠了,那麼這是一個解析器的代碼,與我之前寫過的代碼相似。在我的PC上,它比strtod快6.8倍,比sstream快22.6倍。

double parseFloat(const std::string& input) 
{ 
    const char *p = input.c_str(); 
    if (!*p || *p == '?') 
     return NAN_D; 
    int s = 1; 
    while (*p == ' ') p++; 

    if (*p == '-') { 
     s = -1; p++; 
    } 

    double acc = 0; 
    while (*p >= '0' && *p <= '9') 
     acc = acc * 10 + *p++ - '0'; 

    if (*p == '.') { 
     double k = 0.1; 
     p++; 
     while (*p >= '0' && *p <= '9') { 
      acc += (*p++ - '0') * k; 
      k *= 0.1; 
     } 
    } 
    if (*p) die("Invalid numeric format"); 
    return s * acc; 
}