Fortran (разработанный для научных вычислений) имеет встроенный оператор питания, и, насколько я знаю, компиляторы Fortran обычно оптимизируют повышение до целочисленных степеней аналогично тому, что вы описываете. К сожалению, в C / C ++ нет оператора power, только библиотечная функция pow()
. Это не мешает умным компиляторам обрабатывать их pow
особым образом и ускорять вычисления для особых случаев, но, похоже, они делают это реже ...
Несколько лет назад я пытался сделать более удобным расчет целочисленных степеней оптимальным способом и придумал следующее. Это C ++, а не C, и все еще зависит от умения компилятора оптимизировать / встроить вещи. В любом случае, надеюсь, вы найдете это полезным на практике:
template<unsigned N> struct power_impl;
template<unsigned N> struct power_impl {
template<typename T>
static T calc(const T &x) {
if (N%2 == 0)
return power_impl<N/2>::calc(x*x);
else if (N%3 == 0)
return power_impl<N/3>::calc(x*x*x);
return power_impl<N-1>::calc(x)*x;
}
};
template<> struct power_impl<0> {
template<typename T>
static T calc(const T &) { return 1; }
};
template<unsigned N, typename T>
inline T power(const T &x) {
return power_impl<N>::calc(x);
}
Разъяснение для любопытных: это не находит оптимального способа вычисления степеней, но поскольку поиск оптимального решения является NP-полной задачей, и это все равно стоит делать только для малых держав (в отличие от использования pow
), нет причин для суеты с деталями.
Тогда просто используйте это как power<6>(a)
.
Это позволяет легко набирать полномочия (не нужно прописывать 6 a
с паренами) и позволяет проводить оптимизацию такого рода, -ffast-math
если у вас есть что-то зависящее от точности, например, скомпенсированное суммирование (пример, где порядок операций важен) ,
Вы также можете забыть, что это C ++, и просто использовать его в программе на C (если он компилируется с помощью компилятора C ++).
Надеюсь, что это может быть полезно.
РЕДАКТИРОВАТЬ:
Вот что я получаю от моего компилятора:
Для a*a*a*a*a*a
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
Для (a*a*a)*(a*a*a)
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm0, %xmm0
Для power<6>(a)
,
mulsd %xmm0, %xmm0
movapd %xmm0, %xmm1
mulsd %xmm0, %xmm1
mulsd %xmm0, %xmm1