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)
。
这使得输入幂很容易(不需要a
用括号来拼写6 s),并且使您可以进行这种优化,而-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