Один из способов заставить компилятор оптимизировать умножения на 0 и 1 - это вручную развернуть цикл. Для простоты воспользуемся
#include <array>
#include <cstddef>
constexpr std::size_t n = 12;
using Array = std::array<double, n>;
Затем мы можем реализовать простую функцию dot
, используя выражения свертки (или рекурсию, если они недоступны):
<utility>
template<std::size_t... is>
double dot(const Array& x, const Array& y, std::index_sequence<is...>)
{
return ((x[is] * y[is]) + ...);
}
double dot(const Array& x, const Array& y)
{
return dot(x, y, std::make_index_sequence<n>{});
}
Теперь давайте посмотрим на вашу функцию
double test(const Array& b)
{
const Array a{1}; // = {1, 0, ...}
return dot(a, b);
}
С -ffast-math
gcc 8.2 производит :
test(std::array<double, 12ul> const&):
movsd xmm0, QWORD PTR [rdi]
ret
clang 6.0.0 идет в том же духе:
test(std::array<double, 12ul> const&): # @test(std::array<double, 12ul> const&)
movsd xmm0, qword ptr [rdi] # xmm0 = mem[0],zero
ret
Например, для
double test(const Array& b)
{
const Array a{1, 1}; // = {1, 1, 0...}
return dot(a, b);
}
получаем
test(std::array<double, 12ul> const&):
movsd xmm0, QWORD PTR [rdi]
addsd xmm0, QWORD PTR [rdi+8]
ret
Добавление. Clang развертывает цикл for (std::size_t i = 0; i < n; ++i) ...
без всех этих трюков выражений сгиба, gcc не нуждается и нуждается в некоторой помощи.