亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何快速解析C ++中以空格分隔的浮點數?

如何快速解析C ++中以空格分隔的浮點數?

C++
大話西游666 2019-08-27 13:45:28
如何快速解析C ++中以空格分隔的浮點數?我有一個包含數百萬行的文件,每行有3個以空格分隔的浮點數。讀取文件需要花費大量時間,因此我嘗試使用內存映射文件讀取它們,但發現問題不在于IO的速度,而在于解析速度。我當前的解析是獲取流(稱為文件)并執行以下操作float x,y,z;file >> x >> y >> z;Stack Overflow中的某些人建議使用Boost.Spirit,但我找不到任何簡單的教程來解釋如何使用它。我正在嘗試找到一種簡單有效的方法來解析看起來像這樣的行:"134.32 3545.87 3425"我真的很感激一些幫助。我想用strtok來分割它,但我不知道如何將字符串轉換為浮點數,我不太確定它是最好的方法。我不介意解決方案是否會提升。我不介意它是不是有史以來最有效的解決方案,但我確信它可以加倍速度。提前致謝。
查看完整描述

3 回答

?
牛魔王的故事

TA貢獻1830條經驗 獲得超3個贊

如果轉換是瓶頸(這很可能),您應該首先使用標準中的不同可能性。從邏輯上講,人們會期望它們非常接近,但實際上,它們并不總是:

  • 你已經確定std::ifstream太慢了。

  • 將內存映射數據轉換為a std::istringstream 幾乎肯定不是一個好的解決方案; 您首先必須創建一個字符串,它將復制所有數據。

  • 編寫自己streambuf的內容直接從內存中讀取,無需復制(或使用已棄用的std::istrstream)可能是一種解決方案,但如果問題確實是轉換......這仍然使用相同的轉換例程。

  • 您可以隨時嘗試fscanf,或scanf在您的內存映射流上。根據實現,它們可能比各種istream實現更快。

  • 可能比任何這些都要快strtod。無需為此進行標記:strtod跳過前導空格(包括'\n'),并且具有out參數,其中放置第一個未讀取的字符的地址。結束條件有點棘手,你的循環可能看起來有點像:

    char * begin; //設置為指向mmap的數據...
                    //你還必須安排一個'\ 0'
                    //跟蹤數據 這可能是
                    //最困難的問題
    char * end;
    errno = 0;
    double tmp = strtod(開始,結束);
    while(errno == 0 && end!= begin){
        //用tmp做任何事情......
        begin = end;
        tmp = strtod(開始,結束);
    }

如果這些都不夠快,您將不得不考慮實際數據。它可能有一些額外的約束,這意味著你可以編寫一個比一般更快的轉換例程; 例如strtod,必須處理固定和科學,即使有17位有效數字,它必須100%準確。它還必須是特定于語言環境的。所有這些都增加了復雜性,這意味著需要添加代碼來執行。但要注意:編寫一個有效且正確的轉換例程,即使對于一組有限的輸入,也是非常重要的; 你真的必須知道你在做什么。

編輯:

出于好奇,我進行了一些測試。除了前面提到的解決方案之外,我還編寫了一個簡單的自定義轉換器,它只處理固定點(不科學),小數點后最多五位數,小數點前的值必須符合int

doubleconvert( char const* source, char const** endPtr ){
    char* end;
    int left = strtol( source, &end, 10 );
    double results = left;
    if ( *end == '.' ) {
        char* start = end + 1;
        int right = strtol( start, &end, 10 );
        static double const fracMult[] 
            = { 0.0, 0.1, 0.01, 0.001, 0.0001, 0.00001 };
        results += right * fracMult[ end - start ];
    }
    if ( endPtr != nullptr ) {
        *endPtr = end;
    }
    return results;}

(如果你真的使用它,你肯定應該添加一些錯誤處理。這只是為了實驗目的而迅速被淘汰,讀取我生成的測試文件,沒有 別的。)

接口正好是strtod簡化編碼的接口。

我在兩個環境中運行基準測試(在不同的機器上,所以任何時候的絕對值都不相關)。我得到了以下結果:

在Windows 7下,使用VC 11(/ O2)編譯:

Testing Using fstream directly (5 iterations)...
    6.3528e+006 microseconds per iterationTesting Using fscan directly (5 iterations)...
    685800 microseconds per iterationTesting Using strtod (5 iterations)...
    597000 microseconds per iterationTesting Using manual (5 iterations)...
    269600 microseconds per iteration

在Linux 2.6.18下,使用g ++ 4.4.2(-O2,IIRC)編譯:

Testing Using fstream directly (5 iterations)...
    784000 microseconds per iterationTesting Using fscanf directly (5 iterations)...
    526000 microseconds per iterationTesting Using strtod (5 iterations)...
    382000 microseconds per iterationTesting Using strtof (5 iterations)...
    360000 microseconds per iterationTesting Using manual (5 iterations)...
    186000 microseconds per iteration

在所有情況下,我正在讀取554000行,每行有3個隨機生成的浮點數[0...10000)。

最引人注目的是之間的巨大的差異 fstreamfscanWindows下(與之間的差異相對較小fscanstrtod)。第二件事是兩個平臺上簡單的自定義轉換功能獲得了多少。必要的錯誤處理會使其減慢一點,但差異仍然很大。我期待一些改進,因為它不能處理標準轉換例程所做的很多事情(比如科學格式,非常非常小的數字,Inf和NaN,i18n等),但不是這么多。


查看完整回答
反對 回復 2019-08-27
?
紫衣仙女

TA貢獻1839條經驗 獲得超15個贊

在開始之前,請確認這是應用程序的慢速部分并獲得測試工具,以便您可以衡量改進。

boost::spirit在我看來,這對你來說太過分了。嘗試fscanf

FILE* f = fopen("yourfile");if (NULL == f) {
   printf("Failed to open 'yourfile'");
   return;}float x,y,z;int nItemsRead = fscanf(f,"%f %f %f\n", &x, &y, &z);if (3 != nItemsRead) {
   printf("Oh dear, items aren't in the right format.\n");
   return;}


查看完整回答
反對 回復 2019-08-27
  • 3 回答
  • 0 關注
  • 702 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號