Fortran (progettato per il calcolo scientifico) ha un operatore di potenza integrato e, per quanto ne so, i compilatori di Fortran ottimizzano comunemente l'innalzamento a potenze intere in modo simile a quello che descrivi. C / C ++ purtroppo non ha un operatore di potenza, solo la funzione di libreria pow()
. Ciò non impedisce ai compilatori intelligenti di trattare in modo pow
speciale e di elaborarlo in modo più rapido per casi speciali, ma sembra che lo facciano meno comunemente ...
Alcuni anni fa stavo cercando di rendere più conveniente il calcolo di potenze intere in modo ottimale, e ho trovato quanto segue. È C ++, non C, e dipende ancora dal fatto che il compilatore sia in qualche modo intelligente su come ottimizzare / incorporare le cose. Comunque, spero che potresti trovarlo utile in pratica:
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);
}
Chiarimento per i curiosi: questo non trova il modo ottimale per calcolare i poteri, ma dal momento che trovare la soluzione ottimale è un problema NP-completo e questo vale la pena fare comunque solo per piccoli poteri (al contrario dell'uso pow
), non c'è motivo di agitarsi con il dettaglio.
Quindi usalo come power<6>(a)
.
Ciò semplifica la digitazione dei poteri (non è necessario precisare 6 a
s con parentesi) e consente di avere questo tipo di ottimizzazione senza -ffast-math
nel caso in cui si abbia qualcosa che dipende dalla precisione come la somma compensata (un esempio in cui l'ordine delle operazioni è essenziale) .
Probabilmente puoi anche dimenticare che questo è C ++ e usarlo nel programma C (se si compila con un compilatore C ++).
Spero che questo possa essere utile.
MODIFICARE:
Questo è ciò che ottengo dal mio compilatore:
Per a*a*a*a*a*a
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
Per (a*a*a)*(a*a*a)
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm0, %xmm0
Per power<6>(a)
,
mulsd %xmm0, %xmm0
movapd %xmm0, %xmm1
mulsd %xmm0, %xmm1
mulsd %xmm0, %xmm1