Fortran (zaprojektowany do obliczeń naukowych) ma wbudowany operator mocy i, o ile wiem, kompilatory Fortran zwykle optymalizują podnoszenie do mocy całkowitych w podobny sposób, jak to opisujesz. C / C ++ niestety nie ma operatora mocy, tylko funkcję biblioteki pow()
. Nie uniemożliwia to inteligentnym kompilatorom pow
specjalnego traktowania i obliczania go szybciej w szczególnych przypadkach, ale wygląda na to, że robią to rzadziej ...
Kilka lat temu próbowałem uczynić wygodniejszym obliczanie mocy całkowitych w optymalny sposób i wymyśliłem następujące. Jest to C ++, a nie C, i nadal zależy od tego, czy kompilator jest dość inteligentny w zakresie optymalizacji / wstawiania rzeczy. W każdym razie, mam nadzieję, że okaże się przydatny w praktyce:
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);
}
Wyjaśnienie dla ciekawskich: nie znajduje to optymalnego sposobu obliczania mocy, ale ponieważ znalezienie optymalnego rozwiązania jest problemem NP-zupełnym i warto to robić tylko dla małych mocy (w przeciwieństwie do używania pow
), nie ma powodu do zamieszania ze szczegółami.
Następnie użyj go jako power<6>(a)
.
Ułatwia to wpisywanie mocy (nie trzeba przeliterować 6 a
s za pomocą parens) i pozwala na tego rodzaju optymalizację bez -ffast-math
przypadku, gdy masz coś zależnego od precyzji, np. Sumowanie skompensowane (przykład, w którym niezbędna jest kolejność operacji) .
Prawdopodobnie możesz również zapomnieć, że jest to C ++ i po prostu użyć go w programie C (jeśli kompiluje się z kompilatorem C ++).
Mam nadzieję, że to może być przydatne.
EDYTOWAĆ:
Oto, co otrzymuję od mojego kompilatora:
dla a*a*a*a*a*a
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
dla (a*a*a)*(a*a*a)
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm0, %xmm0
dla power<6>(a)
,
mulsd %xmm0, %xmm0
movapd %xmm0, %xmm1
mulsd %xmm0, %xmm1
mulsd %xmm0, %xmm1