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