简体   繁体   中英

Linear search vs binary search real time performance in C++

Getting totally unexpected results while comparing binary search vs linear search's real time performance in C++ using the code below -

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";
}

Compiling without optimisation, getting following output -

Linear search: 1000 values 1848621us
Binary search: 1000 values 24975us

When compiled with -O3 optimisation, getting this output -

Linear search: 1000 values 0us
Binary search: 1000 values 13424us

I understand that for small array size, binary search may be expensive than linear but can't understand reason for difference of this magnitude by adding -O3

The compiler manages to realize that your linear search is a noop (it has no side effects) and converts it to doing nothing. So it takes zero time.

To fix that, consider taking the return value and adding it up, then printing it outside the timing block.

I benchmarked your code with https://quick-bench.com and binary search is much faster (for m = 100 , it breaks for m = 1000 ). That's my benchmark code:

int linear_search(uint64_t* val, int s, int e, uint64_t k) {
    while (s < e) {
      if (!std::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 (std::less<uint64_t>()(val[mid], k)) {
        s = mid + 1;
      } else {
        e = mid;
      }
    }
    return s;
}

constexpr int m = 100;
uint64_t val[m];
uint64_t key = rand();
void init() {
  static bool isInitialized = false;
  if (isInitialized) return;
  for(int i = 0; i < m;i++) {
    val[i] = rand();
  }
  std::sort(val, val + m);
  isInitialized = true;
}

static void Linear(benchmark::State& state) {
  init();
  for (auto _ : state) {
    int result = linear_search(val, 0, m - 1, key);
    benchmark::DoNotOptimize(result);
  }
}
BENCHMARK(Linear);

static void Binary(benchmark::State& state) {
  init();
  for (auto _ : state) {
    int result = binary_search(val, 0, m - 1, key);
    benchmark::DoNotOptimize(result);
  }
}
BENCHMARK(Binary);

and the result:

在此处输入图像描述

Only the code inside for (auto _: state) { is benchmarked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM