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