[英]Optimizing this 'statistical coincidence' finding algorithm
目標
下面的代碼旨在從高斯分布中獲取隨機數的vector<vector<float> >
,並執行以下操作:
同時遍歷向量的所有n
列,直到遇到第一個超過某個閾值的值。
繼續迭代,直到 a) 您遇到超過該閾值的第二個值,使得該值來自與第一個找到的值不同的列,或者 b) 您超過某個最大迭代次數。
在 a) 的情況下,繼續迭代直到 c) 您發現第三個值超過閾值,使得該值來自與第一個找到的值和第二個找到的值不同的列,或者 b) 您超過了某個最大數量從第一個找到的值開始迭代。 在 b) 的情況下重新開始,除了這次在第一個找到的值之后的一行開始迭代。
在 c) 的情況下,將一個計數器加一,並向前跳轉一些x
行。 在 d) 的情況下,重新開始,除了這次在第一個找到的值之后的一行開始迭代。
我如何做到這一點:
在我看來,最具挑戰性的部分是確保所有三個值都由一個獨特的列提供。 為了解決這個問題,我使用了std::set
。 我遍歷vector<vector<float> >
的每一行,然后遍歷該行的每一列。 我檢查每列是否有超過閾值的值,並將其列數存儲在 std::set 中。
我繼續迭代。 如果我達到max_iterations
,我跳回到第一個找到的值之后的一個,清空集合,並重置計數器。 如果std::set
的大小為3
,我將一個添加到計數器。
我的問題:
此代碼將需要在大小為數十列和數十萬到數百萬行的多維向量上運行。 截至目前,這是極其緩慢的。 如果可能的話,我想顯着提高性能。
我的代碼:
void findRate(float thresholdVolts){
set<size_t> cache;
vector<size_t> index;
size_t count = 0, found = 0;
for(auto rowItr = waveform.begin(); rowItr != waveform.end(); ++rowItr){
auto &row = *rowItr;
for(auto colnItr = row.begin(); colnItr != row.end(); ++colnItr){
auto &cell = *colnItr;
if(abs(cell/rmsVoltage) >= (thresholdVolts/rmsVoltage)){
cache.insert(std::distance(row.begin(), colnItr));
index.push_back(std::distance(row.begin(), colnItr));
}
}
if(cache.size() == 0) count == 0;
if(cache.size() == 3){
++found;
cache.clear();
if(std::distance(rowItr, output.end()) > ((4000 - count) + 4E+6)){
std::advance(rowItr, ((4000 - count) + 4E+6));
}
}
}
}
您可以在內部循環中立即做一件事。 我知道 rmsVoltage 是一個外部變量,它在 function 的執行過程中是恆定的。
for(auto colnItr = row.begin(); colnItr != row.end(); ++colnItr){
auto &cell = *colnItr;
// you can remove 2 divisions here. Divisions are the slowest
// arithmetic instructions on any cpu
//
// this:
// if(abs(cell/rmsVoltage) >= (thresholdVolts/rmsVoltage)){
//
// becomes this
if (abs(cell) >= thresholdVolts) {
cache.insert(std::distance(row.begin(), colnItr));
index.push_back(std::distance(row.begin(), colnItr));
}
下面一點:為什么要向 size_t 添加浮點常量? 這可能會導致 size_t 的不必要轉換加倍,然后返回到 size_t,一些編譯器可能會處理這個問題,但絕對不是全部。
這些是相對昂貴的操作。
// this:
// if(std::distance(rowItr, output.end()) > ((4000 - count) + 4E+6)){
// std::advance(rowItr, ((4000 - count) + 4E+6));
// }
if (std::distance(rowItr, output.end()) > (4'004'000 - count))
std::advance(rowItr, 4'004'000 - count);
此外,在觀察 memory 中對您的 function 的需求后,您應該使用 vector<>::reserve() 和 set<>::reserve() 為容器緩存和索引預分配一些合理的空間。
你給我們整個算法了嗎? 容器索引的內容不會在任何地方使用。
請讓我知道您通過這些更改獲得了多少時間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.