(-1)^n
多くのアルゴリズムでは、通常は系列の因数として (両方とも整数)を計算する必要があります。つまり、-1
奇数 n と偶数 nの係数です1
。C++ 環境では、次のことがよく見られます。
#include<iostream>
#include<cmath>
int main(){
int n = 13;
std::cout << std::pow(-1, n) << std::endl;
}
どちらが良いですか、それとも通常の慣習ですか? (または、他の何か)、
std::pow(-1, n)
std::pow(-1, n%2)
(n%2?-1:1)
(1-2*(n%2)) // (gives incorrect value for negative n)
編集:
さらに、ユーザー @SeverinPappadeux は、(グローバル?) 配列ルックアップに基づく別の代替案を提案しました。私のバージョンは次のとおりです。
const int res[] {-1, 1, -1}; // three elements are needed for negative modulo results
const int* const m1pow = res + 1;
...
m1pow[n%2]
これで問題が解決するわけではありませんが、発行されたコードを使用することで、いくつかのオプションを破棄できます。
最初は最適化なしで、最終候補は次のとおりです。
1 - ((n & 1) << 1);
(7演算、メモリアクセスなし)
mov eax, DWORD PTR [rbp-20]
add eax, eax
and eax, 2
mov edx, 1
sub edx, eax
mov eax, edx
mov DWORD PTR [rbp-16], eax
と
retvals[n&1];
(5 操作、メモリ -- レジスタ? -- アクセス)
mov eax, DWORD PTR [rbp-20]
and eax, 1
cdqe
mov eax, DWORD PTR main::retvals[0+rax*4]
mov DWORD PTR [rbp-8], eax
最適化 (-O3) を使用
1 - ((n & 1) << 1);
(4演算、メモリアクセスなし)
add edx, edx
mov ebp, 1
and edx, 2
sub ebp, edx
.
retvals[n&1];
(4 つの操作、メモリ -- レジスタ? -- アクセス)
mov eax, edx
and eax, 1
movsx rcx, eax
mov r12d, DWORD PTR main::retvals[0+rcx*4]
.
n%2?-1:1;
(4演算、メモリアクセスなし)
cmp eax, 1
sbb ebx, ebx
and ebx, 2
sub ebx, 1
テストはこちらです。操作をすべてまとめて省略しない意味のあるコードを作成するには、いくつかのアクロバットが必要でした。
結論(とりあえず)
したがって、最終的にはレベルの最適化と表現力に依存します。
1 - ((n & 1) << 1);
常に良いですが、あまり表現力がありません。retvals[n&1];
メモリアクセスには代償を払います。n%2?-1:1;
表現力豊かで優れていますが、最適化のみが必要です。