Fortran (diseñado para computación científica) tiene un operador de potencia incorporado, y que yo sepa, los compiladores de Fortran comúnmente optimizarán la elevación a potencias enteras de manera similar a lo que usted describe. Desafortunadamente, C / C ++ no tiene un operador de energía, solo la función de biblioteca pow()
. Esto no evita que los compiladores inteligentes lo traten pow
especialmente y lo computen de una manera más rápida para casos especiales, pero parece que lo hacen con menos frecuencia ...
Hace algunos años, estaba tratando de hacer más conveniente el cálculo de potencias enteras de manera óptima, y se me ocurrió lo siguiente. Sin embargo, es C ++, no C, y aún depende de que el compilador sea algo inteligente sobre cómo optimizar / alinear las cosas. De todos modos, espero que les resulte útil en la práctica:
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);
}
Aclaración para los curiosos: esto no encuentra la forma óptima de calcular las potencias, pero dado que encontrar la solución óptima es un problema NP-completo y esto solo vale la pena hacerlo para las potencias pequeñas de todos modos (en lugar de usar pow
), no hay razón para preocuparse Con el detalle.
Entonces solo úsalo como power<6>(a)
.
Esto facilita la escritura de poderes (no es necesario deletrear 6 a
s con parens), y le permite tener este tipo de optimización sin -ffast-math
tener que depender de la precisión, como la suma compensada (un ejemplo donde el orden de las operaciones es esencial) .
Probablemente también pueda olvidar que se trata de C ++ y simplemente usarlo en el programa C (si se compila con un compilador de C ++).
Espero que esto pueda ser útil.
EDITAR:
Esto es lo que obtengo de mi compilador:
para a*a*a*a*a*a
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
para (a*a*a)*(a*a*a)
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm0, %xmm0
para power<6>(a)
,
mulsd %xmm0, %xmm0
movapd %xmm0, %xmm1
mulsd %xmm0, %xmm1
mulsd %xmm0, %xmm1