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
s с паренами) и позволяет оптимизировать этот тип без -ffast-math
в случае, если у вас есть что-то зависящее от точности, такое как с компенсацией суммирование (пример, где важен порядок операций).
Возможно, вы также можете забыть, что это C ++, и просто использовать его в программе на C (если он компилируется с помощью компилятора C ++).
Надеюсь, это может быть полезно.
EDIT:
Вот что я получаю от моего компилятора:
Для 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