【发布时间】:2014-07-12 21:38:56
【问题描述】:
所以我有这个函数用于计算统计数据(最小值/最大值/标准/平均值)。现在问题是这通常在 10,000 x 15,000 矩阵上运行。矩阵在类中存储为vector<vector<int> >。现在创建和填充所述矩阵非常快,但是当涉及到统计部分时,它变得非常慢。
例如一次读取一个像素的 geotiff 的所有像素值大约需要 30 秒。 (这涉及到大量复杂的数学运算,以将像素值正确地定位到对应点),计算整个矩阵的统计数据大约需要 6 分钟。
void CalculateStats()
{
//OHGOD
double new_mean = 0;
double new_standard_dev = 0;
int new_min = 256;
int new_max = 0;
size_t cnt = 0;
for(size_t row = 0; row < vals.size(); row++)
{
for(size_t col = 0; col < vals.at(row).size(); col++)
{
double mean_prev = new_mean;
T value = get(row, col);
new_mean += (value - new_mean) / (cnt + 1);
new_standard_dev += (value - new_mean) * (value - mean_prev);
// find new max/min's
new_min = value < new_min ? value : new_min;
new_max = value > new_max ? value : new_max;
cnt++;
}
}
stats_standard_dev = sqrt(new_standard_dev / (vals.size() * vals.at(0).size()) + 1);
std::cout << stats_standard_dev << std::endl;
}
我在这里做了什么可怕的事情吗?
编辑
为了响应 cmets,T 将是一个 int。
编辑 2
我修正了我的标准算法,这是最终产品:
void CalculateStats(const std::vector<double>& ignore_values)
{
//OHGOD
double new_mean = 0;
double new_standard_dev = 0;
int new_min = 256;
int new_max = 0;
size_t cnt = 0;
int n = 0;
double delta = 0.0;
double mean2 = 0.0;
std::vector<double>::const_iterator ignore_begin = ignore_values.begin();
std::vector<double>::const_iterator ignore_end = ignore_values.end();
for(std::vector<std::vector<T> >::const_iterator row = vals.begin(), row_end = vals.end(); row != row_end; ++row)
{
for(std::vector<T>::const_iterator col = row->begin(), col_end = row->end(); col != col_end; ++col)
{
// This method of calculation is based on Knuth's algorithm.
T value = *col;
if(std::find(ignore_begin, ignore_end, value) != ignore_end)
continue;
n++;
delta = value - new_mean;
new_mean = new_mean + (delta / n);
mean2 = mean2 + (delta * (value - new_mean));
// Find new max/min's.
new_min = value < new_min ? value : new_min;
new_max = value > new_max ? value : new_max;
}
}
stats_standard_dev = mean2 / (n - 1);
stats_min = new_min;
stats_max = new_max;
stats_mean = new_mean;
这仍然需要大约 120-130 秒才能完成,但这是一个巨大的改进 :)!
【问题讨论】:
-
T是什么类型?get方法是如何工作的? -
将
vals.at(row)替换为vals[row]将删除范围检查。 -
@Kirill,这将完全解决他的性能问题。如果这当然与性能问题有关。如果不分析代码,他就无法知道真正的问题是什么
-
请记住,像这样计算平均值(尤其是整数)会引入大量错误 - 前几个元素是唯一需要考虑的元素。
-
OHGOD 的评论让我发笑。我不知道为什么。
标签: c++ performance