次の形式の収束級数を考えてみましょう。
sum(((-1)^n)*something)
ここn
で、は反復のインデックスです(n
から1
へinfinity
)。
式を直接実装する場合、std::pow(-1, n)
それはありますが、それを実装するためのより「迅速な」アルゴリズムのトリックはありますか?
次の形式の収束級数を考えてみましょう。
sum(((-1)^n)*something)
ここn
で、は反復のインデックスです(n
から1
へinfinity
)。
式を直接実装する場合、std::pow(-1, n)
それはありますが、それを実装するためのより「迅速な」アルゴリズムのトリックはありますか?
n
偶数か奇数かを確認し、
(n % 2 == 0) ? 1 : -1;
それをします。分岐を避けたい場合は、
1 - 2*(n & 1)
sum(((-1)^n)*something)
これは擬似コードであり、n
sumによってバインドされる変数であると想定しています。
その表記をに拡張してみましょうsum(n <- [0,1,2,3..], ((-1)^n)*f(n))
。おそらく、最初にこれを2つの合計に分割し、それらを合計するのが最善の選択肢です。
sum(n <- [0,2..], ((-1)^n)*f(n)) + sum(n <- [1,3..], ((-1)^n)*f(n))
最初の項では、n
は常に偶数であるため、(-1)^n
常にになります+1
。同様に、第2項では、常にになります-1
。これで、これを次のように書き直すことができます。
sum(n <- [0,2..], f(n)) + sum(n <- [1,3..], -f(n))
2番目の合計のすべての項に定数が乗算されるため、その定数を合計から移動できます。
sum(n <- [0,2..], f(n)) - sum(n <- [1,3..], f(n))
2*m
ここで、これらの合計が同じインデックスシーケンスを取り、と2*m+1
をn
次のように置き換えていることを確認しましょう。
sum(m <- [0,1..], f(2*m)) - sum(m <- [0,1..], f(2*m+1))
これで、これらの合計を再び結合できます。
sum(m <- [0,1..], f(2*m) - f(2*m+1))
または、疑似Cが必要な場合:
T result = 0;
for(m = 0; m < limit; m+=2) {
result += f(m);
result -= f(m+1);
}
これにより、ほとんどの人がここで示唆しているように、+1
またはによる乗算を節約できます。-1
シーケンスは収束しているので、余分な項をとっても、答えの正しさに悪影響を与えることはありません。
ええ、魔法のトリックがあります:偶数の(-1)^n == 1
場合に限りn
、そして奇数の(-1)^n == -1
場合にのみn
。したがって:
int p = (n % 2 == 0) ? 1 : -1;
sum(p*something)
この用語は、奇数または偶数の場合に((-1)^n)*something
評価されます。-something
n
something
n
n & 1 ? -something : something
something
が定数値の場合、の最後の値が奇数のとき、または偶数の被加数に対してsum(((-1)^n)*something)
評価されます。-something
n
0
n & 1 ? -something : 0
この場合、シリーズは収束しません。
これをループで実行している場合は、次のようにすることができます。
x = 1; // Assuming we start on n = 0
for(...) // or while(...)
{
sum += x * something;
x = -x;
}
これは、nのチェックを実行するよりもはるかに高速である可能性があります。もちろん、n個の値すべてが繰り返されることを前提としており、あちこちでいくつかスキップすることはありません...