В этом фрагменте кода я сравниваю производительность двух функционально идентичных циклов:
for (int i = 1; i < v.size()-1; ++i) {
  int a = v[i-1];
  int b = v[i];
  int c = v[i+1];
  if (a < b  &&  b < c)
    ++n;
}
и
for (int i = 1; i < v.size()-1; ++i) 
  if (v[i-1] < v[i]  &&  v[i] < v[i+1])
    ++n;
Первый работает значительно медленнее, чем второй, на множестве разных компиляторов С++ с флагом оптимизации, установленным на O2:
- второй цикл составляет около 330% медленнее теперь с Clang 3.7.0
 - второй цикл примерно на 2% медленнее с gcc 4.9.3
 - второй цикл примерно на 2% медленнее с Visual С++ 2015
 
Я озадачен тем, что современные оптимизаторы С++ имеют проблемы с обработкой этого случая. Какие-нибудь подсказки почему? Должен ли я писать уродливый код без использования временных переменных, чтобы получить максимальную производительность?
Использование временных переменных делает код быстрее, а иногда и резко. Что происходит?
Полный код, который я использую, приведен ниже:
#include <algorithm>
#include <chrono>
#include <random>
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;
using namespace std::chrono;
vector<int> v(1'000'000);
int f0()
{
  int n = 0;
  for (int i = 1; i < v.size()-1; ++i) {
    int a = v[i-1];
    int b = v[i];
    int c = v[i+1];
    if (a < b  &&  b < c)
      ++n;
  }
  return n;
}
int f1()
{
  int n = 0;
  for (int i = 1; i < v.size()-1; ++i) 
    if (v[i-1] < v[i]  &&  v[i] < v[i+1])
      ++n;
  return n;
}
int main()
{
  auto benchmark = [](int (*f)()) {
    const int N = 100;
    volatile long long result = 0;
    vector<long long>  timings(N);
    for (int i = 0; i < N; ++i) {
      auto t0 = high_resolution_clock::now(); 
      result += f();
      auto t1 = high_resolution_clock::now(); 
      timings[i] = duration_cast<nanoseconds>(t1-t0).count();
    }
    sort(timings.begin(), timings.end());
    cout << fixed << setprecision(6) << timings.front()/1'000'000.0 << "ms min\n";
    cout << timings[timings.size()/2]/1'000'000.0 << "ms median\n" << "Result: " << result/N << "\n\n";
  };
  mt19937                    generator   (31415);   // deterministic seed
  uniform_int_distribution<> distribution(0, 1023);
  for (auto& e: v) 
    e = distribution(generator);
  benchmark(f0);
  benchmark(f1);
  cout << "\ndone\n";
  return 0;
}