【发布时间】:2021-04-30 08:09:41
【问题描述】:
使用下面的代码比较二分搜索与线性搜索在 C++ 中的实时性能时得到完全出乎意料的结果 -
typedef std::chrono::microseconds us;
int linear_search(uint64_t* val, int s, int e, uint64_t k) {
while (s < e) {
if (!less<uint64_t>()(val[s], k)) {
break;
}
++s;
}
return {s};
}
int binary_search(uint64_t* val, int s, int e, uint64_t k) {
while (s != e) {
const int mid = (s + e) >> 1;
if (less<uint64_t>()(val[mid], k)) {
s = mid + 1;
} else {
e = mid;
}
}
return {s};
}
int main() {
// Preparing data
int iter = 1000000;
int m = 1000;
uint64_t val[m];
for(int i = 0; i < m;i++) {
val[i] = rand();
}
sort(val, val + m);
uint64_t key = rand();
// Linear search time computation
auto start = std::chrono::system_clock::now();
for (int i = 0; i < iter; i++) {
linear_search(val, 0, m - 1, key);
}
auto end = std::chrono::system_clock::now();
auto elapsed_us = std::chrono::duration_cast<us>(end - start);
std::cout << "Linear search: " << m << " values "
<< elapsed_us.count() << "us\n";
// Binary search time computation
start = std::chrono::system_clock::now();
for (int i = 0; i < iter; i++) {
binary_search(val, 0, m - 1, key);
}
end = std::chrono::system_clock::now();
elapsed_us = std::chrono::duration_cast<us>(end - start);
std::cout << "Binary search: " << m <<" values "
<< elapsed_us.count() << "us\n";
}
编译不优化,得到以下输出-
Linear search: 1000 values 1848621us
Binary search: 1000 values 24975us
当使用 -O3 优化编译时,得到这个输出 -
Linear search: 1000 values 0us
Binary search: 1000 values 13424us
我知道对于小数组大小,二进制搜索可能比线性搜索要昂贵,但无法通过添加 -O3 来理解这种幅度差异的原因
【问题讨论】:
-
优化了,对输出做一些事情,这样编译器就不会完全跳过这个块
-
您没有使用线性搜索的结果,因此编译器会在打开优化时删除该部分,令人费解的部分是为什么二进制搜索部分没有发生同样的情况
-
我推荐the compiler explorer,它可以让您查看生成的汇编代码以了解发生了什么。
-
@largest_prime_is_463035818 val 是由指针获取的,如果变量被引用,编译器不能排除副作用,二进制搜索是最后一个并且在它之后没有对 val 的引用。
-
@AlessandroTeruzzi 是的,但不是。编译器确实优化了
linear_search,它首先出现,两者都使用指针。一旦它确实优化了linear_search,它也可以删除binary_search
标签: c++ compiler-optimization binary-search linear-search