Fortran (призначений для наукових обчислень) має вбудований оператор живлення, і наскільки я знаю, компілятори Fortran зазвичай оптимізують підвищення до цілих потужностей аналогічно тому, що ви описуєте. Нажаль, C / C ++ не мають оператора живлення, лише функцію бібліотеки 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