我有以下递推公式:
f(0) = 0
f(1) = 1
f(n) = n + f(floor(n/2))
可以用代码表示为:
int f(int n) {
int s = 0;
for (; n; n >>= 1)
s += n;
return s;
}
是否有封闭表单可以让我一步计算f(n)
?
如果没有,我还能做些什么来更快地计算f(n)
?
答案 0 :(得分:6)
在OEIS上搜索给出了这个系列:
A005187:a(n)= a([n / 2])+ n;也是扩张的分母 1 / sqrt(1-x)是2 ^ a(n);也是2n - 二进制扩展的1的数量 2n个。
所以第二部分给出了2*n - bitcount(2*n)
的公式。您可以使用一些有效的bitcount实现来计算它,例如gcc的__builtin_popcount
。
答案 1 :(得分:2)
还要注意bitcount(2n)= bitcount(n)
,推导如下:
对于j = 0 ... N ,设n = sum(b [j] 2 ^ j)假设b [N] = 1. define
(a)F(n)= n + F(n / 2)= n + n / 2 + n / 4 + ... = 2 * n - (1/2 + 1/4 + ... 1/2 ^ N)按几何系列
这个函数F是一个实值函数。现在,对于设置的每个比特b [j],floor函数减去b [j](sum(1/2 ^ k,k = 1 ... j + 1))。这是因为它实际上取出了1/2,但随着它的传播,随后的术语被添加。
所以
(b)f(n)= floor(F(n)-sum(b [j] sum(1/2 ^ k,k = 1 ... j + 1),j = 0 ... N-1)
将(a)代入(b)代表
(c)f(n)= floor(2n - (1/2 + 1/4 + ...... 1/2 ^(N + 1)) - sum < / em>(b [j](sum(1/2 ^(k),对于k = 1..j + 1),对于j = 0 ... N-1))
好的,这部分很酷!观察到当b [j]为1时,如果你将粗体表达式中的1/2 ^(j + 1)隐藏到斜体总和中,则总和内的总和变为1,这意味着b [j](sum(1/2 ^(k),对于k = 1..j + 1),对于j = 0 ... N-1)= sum(b [j],对于j = 0 ... N-1)
因此等式(c)简化为
f(n) = floor(2*n - sum(b[j], for j=0...N-1) - remainder)
f(n) = 2*n - bitcount(n-2^N) - 1 ; because remainder >0 and <1
f(n) = 2*n - bitcount(n) ; b[N]=1, so bitcount(n)=bitcount(n-2^N)+1
其中,余数是和(1/2 ^ j,j = 1,... N + 1和b [j-1] == 0),但是该总和总是> 0且<&lt; 0。 1(最多为1-1 / 2 ^(N + 2)且至少为1/2 ^(N + 1),因此它可以移出地板-1。
并且还要注意,bitcount运行时间可以等于设置的位数(http://gurmeet.net/puzzles/fast-bit-counting-routines/)。有些处理器将它作为单独的指令。
不确定乳胶是否适用于此,但没有数学符号会很痛苦。我不得不编辑它,因为总是看起来不对劲。
答案 2 :(得分:1)
The function grows as follows -
f(n) = n + f(n/2)
f(n/2) can be further simplified as -
n/2 + f(n/4)
If we keep doing this, we will see n + n/2 + n/4 + n/8.....upto log n terms
= n (1 + 1/2 + 1/4 + 1/8...log n terms)
= n[ (1- (1/2)^log n)/(1/2)]
= 2n [1 - (1/2)^log n]
The term (1/2)^log n will become smaller and smaller as n increases, therefore the 2n term dominates. Hence f(n) belongs to big Theta (n)