【问题标题】:Is there a closed form for f(n) = n + f(floor(n/2))?f(n) = n + f(floor(n/2)) 是否有封闭形式?
【发布时间】:2012-12-11 05:40:33
【问题描述】:

我有以下递归公式:

  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)

【问题讨论】:

  • 这是oeis.org/A005187
  • O(log N) 复杂度有什么问题?
  • 你能详细说明你对这些数字的使用吗?如果你的范围相当连续或很小,你也许可以摆脱记忆。

标签: c performance recurrence


【解决方案1】:

OEIS 上搜索得到这个系列:

A005187: a(n) = a([n/2]) + n;也是扩展的分母 1/sqrt(1-x) 是 2^a(n);还有 2n - 二进制展开中 1 的个数 2n.

所以第二部分给出了2*n - bitcount(2*n)的公式。您可以使用一些有效的位计数实现来计算这个,例如 gcc 的__builtin_popcount

【讨论】:

    【解决方案2】:

    还要注意 bitcount(2n) = bitcount(n)

    推导如下:

    让 n = sum(b[j] 2^j) for j=0...N

    假设 b[N] = 1. 定义

    (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(b[j] (sum(1/2^(k), for k=1..j+1), for j=0...N-1))

    好的,这部分很酷!观察当b[j]为1时,如果把粗体表达式中的1/2^(j+1)偷偷到斜体的sum里面,sum里面的sum变成1,也就是说

    b[j] (sum(1/2^(k), for k=1..j+1), for j=0...N-1) = sum(b[j], for 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
    

    其中余数是 sum(1/2^j, j=1,..N+1 and b[j-1]==0),但这个总和总是 >0 且

    还要注意,bitcount 运行时间可以等于设置的位数 (http://gurmeet.net/puzzles/fast-bit-counting-routines/)。一些处理器将其作为单独的指令。

    不确定乳胶是否在这里有效,但没有数学符号会很痛苦。我一直不得不编辑它,因为看起来总是有问题。

    【讨论】:

      【解决方案3】:
      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)
      

      【讨论】:

        猜你喜欢
        • 2015-08-13
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        • 2012-04-13
        • 1970-01-01
        • 2020-08-05
        • 1970-01-01
        • 2012-09-29
        相关资源
        最近更新 更多