考虑以下形式的收敛系列:
sum(((-1)^n)*something)
其中n
是迭代索引(n
从1
变为infinity
)。
如果我们实现direclty公式,我们有std::pow(-1, n)
但是有更多“快速”的算法技巧来实现它吗?
答案 0 :(得分:13)
检查n
是偶数还是奇数,
(n % 2 == 0) ? 1 : -1;
做到了。如果你想避免分支,
1 - 2*(n & 1)
答案 1 :(得分:6)
我假设sum(((-1)^n)*something)
是伪代码,而n
是一个受和的约束变量。
让我们将该符号扩展为sum(n <- [0,1,2,3..], ((-1)^n)*f(n))
。你最好的选择可能是首先把它分成两个,你加在一起:
sum(n <- [0,2..], ((-1)^n)*f(n)) + sum(n <- [1,3..], ((-1)^n)*f(n))
在第一个字词中,n
始终是偶数,因此(-1)^n
始终为+1
。类似地,在第二个词中,它总是-1
。我们现在可以按如下方式重写:
sum(n <- [0,2..], f(n)) + sum(n <- [1,3..], -f(n))
由于第二个和中的每个项乘以一个常数,我们可以将该常数移出总和:
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
,正如大多数人似乎在此建议的那样。由于你的序列是收敛的,所以加一个额外的术语不应该对答案的正确性产生负面影响。
答案 2 :(得分:1)
是的,有一个神奇的伎俩:(-1)^n == 1
当且仅当n
是偶数时,(-1)^n == -1
当且仅当n
是奇数时。因此:
int p = (n % 2 == 0) ? 1 : -1;
sum(p*something)
答案 3 :(得分:1)
对于奇数((-1)^n)*something
,-something
一词评估为n
,对{偶数something
评估为n
:
n & 1 ? -something : something
如果something
是一个常数值,那么当sum(((-1)^n)*something)
的最后一个值为奇数时,-something
会计算为n
,对于偶数,0
会计算为n & 1 ? -something : 0
of summands:
{{1}}
在这种情况下,系列不会收敛。
答案 4 :(得分:1)
如果您在循环中执行此操作,则可以执行以下操作:
x = 1; // Assuming we start on n = 0
for(...) // or while(...)
{
sum += x * something;
x = -x;
}
这很可能比对n进行检查要快得多 - 当然,它假设所有n个值都被迭代,并且你不会在这里和那里跳过一些......