在数组中找到两个最小的int64元素的最快方法
Fastest way of finding two minimum int64 elements in array
我的数组大小从1000到10000 (1k ..)10 k)。每个元素都是int64。我的任务是找到数组中最小的两个元素,最小的元素和最小的元素。
我想在Intel Core2或Corei7 (cpu模式为64位)的c++中获得最快的单线程代码。
这个函数(从数组中获取最小的2个)是热点,它嵌套在两个或三个具有巨大迭代计数的for循环中。
当前代码如下:
int f()
{
int best; // index of the minimum element
int64 min_cost = 1LL << 61;
int64 second_min_cost = 1LL << 62;
for (int i = 1; i < width; i++) {
int64 cost = get_ith_element_from_array(i); // it is inlined
if (cost < min_cost) {
best = i;
second_min_cost = min_cost;
min_cost = cost;
} else if (cost < second_min_cost) {
second_min_cost = cost;
}
}
save_min_and_next(min_cost, best, second_min_cost);
}
看partial_sort
和nth_element
std::vector<int64_t> arr(10000); // large
std::partial_sort(arr.begin(), arr.begin()+2, arr.end());
// arr[0] and arr[1] are minimum two values
如果你只想要第二个最小的值,nth_element就是你要的
尝试反转if:
if (cost < second_min_cost)
{
if (cost < min_cost)
{
}
else
{
}
}
您可能应该用相同的值初始化min_cost和second_min_cost,使用int64的最大值(或者更好地使用qbert220的建议)
一些小事情(可能已经发生了,但我想可能值得一试)
-
稍微展开循环—例如,以8步迭代(即一次缓存行),预取主体中的下一个缓存行,然后处理8项。为了避免大量检查,确保结束条件是8的倍数,剩余的项目(小于8)应该在循环外处理-展开…
-
对于不感兴趣的项目,你在身上做了两道检查,也许你可以修剪成1道?即,如果
cost
小于second_min
,则检查min
-否则无需麻烦…
您最好先检查second_min_cost,因为它是唯一需要修改结果的条件。这样,您将在主循环中获得一个分支,而不是两个分支。这应该很有帮助。
除此之外,没有什么可以优化的,你已经接近最优了。展开可能会有帮助,但我怀疑它在这种情况下是否会带来任何显著的优势。
所以它变成了:
int f()
{
int best; // index of the minimum element
int64 min_cost = 1LL << 61;
int64 second_min_cost = 1LL << 62;
for (int i = 1; i < width; i++) {
int64 cost = get_ith_element_from_array(i); // it is inlined
if (cost < second_min_cost)
{
if (cost < min_cost)
{
best = i;
second_min_cost = min_cost;
min_cost = cost;
}
else second_min_cost = cost;
}
save_min_and_next(min_cost, best, second_min_cost);
}
确保您的数组读取是正常的,这样就不会引入不必要的缓存丢失。
这段代码应该非常接近现代CPU的带宽限制,假设数组读取很简单。您需要分析和/或计算它是否仍然有任何CPU优化的空间。
你有什么,是O(n)
和最佳的随机数据。也就是说,你已经有最快的了。
唯一可以改善这一点的方法是给你的数组赋予某些属性,例如,保持它一直排序或使它成为一个堆。
好处是你的算法只扫描一次数字。你是最优的。
速度慢的一个重要原因可能来自元素的排列方式。如果它们在一个数组中,我指的是一个C数组(或c++向量),其中所有元素都是连续的,你向前扫描它们,那么内存方面你也是最优的。否则,你可能会有一些惊喜。例如,如果您的元素在链表中,或者分散聚集,那么您可能会对内存访问进行惩罚。
- Mongodb c++驱动程序:如何查询元素的数组
- 从不同线程使用int64的不同字节安全吗
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 使用strcpy将char数组的元素复制到另一个数组
- 使用不带参数的函数访问结构元素
- 给定n个元素的m个集合.在C++中找到出现在最大集合数中的元素
- C++如何通过用户输入删除列表元素
- lower_bound()返回最后一个元素
- 基于多个条件处理地图中的所有元素
- 调整大小后指向元素值的指针unordered_map有效?
- 使用std::transform将一个范围的元素添加到另一个范围中
- 使用函数"remove"删除重复元素
- 具有最大子序列大小的序列,每个元素都相同
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 如何将元素添加到数组的线程安全函数?
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- 我想访问std::unique_ptr中的一个特定元素
- 如何通过 getter 函数删除矢量的元素?
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 在数组中找到两个最小的int64元素的最快方法