【问题标题】:Why must a ring buffer size be a power of 2?为什么环形缓冲区大小必须是 2 的幂?
【发布时间】:2012-05-10 04:38:10
【问题描述】:

为什么环形缓冲区的大小必须是 2 的幂?

【问题讨论】:

  • 是什么让你如此确定它必须是 2 的幂?
  • 如果缓冲区数组的大小是 2 的幂,环形缓冲区将使用更有效的掩码而不是昂贵的模运算来维护自身。
  • OP应该解释为什么他认为(谁说的?)大小必须是2的幂,他应该标记一个有效的答案。我仍然认为这个问题(如果有道理的话)可以用“因为x mod 2^n可以实现为x & (2^n - 1),假设项目存储在索引从0到2^n-1的数组中的实现。然而,对于现代 CPU 和编译器来说,这实际上并不会产生太大的影响。

标签: circular-buffer


【解决方案1】:

使用下面详述的方法必须是 2 的幂。不必如此。

常见的方法类似于“if (index >= size) { index = size - index; }”(大小为 10,索引为 10,结果索引为 0)。相对于以下方法,这速度较慢且容易出错。

使用 2 的幂可以让我们利用以下优势:

size = 32
bin(size) => '00100000'

mask = size - 1;
bin(mask) => '00011111'

使用按位和应用此掩码,随着索引的增长,我们可以仅隔离包含 0 - 31 范围内数字的位:

index = 4
bin(4 & mask) => '00000100' (4)

# index 32 wraps.  note here that we do no bounds checking, 
# no manipulation of the index is necessary.  we can simply 
# and safely use the result.
index = 32
bin(index & mask) => '00000000' (0)

index = 33
bin(index & mask) => '00000001' (1)

index = 64
bin(index & mask) => '00000000' (0)

index = 65
bin(index & mask) => '00000001' (1)

这种方法不需要比较,没有分支,并且是安全的(结果索引总是在范围内)。它具有不破坏信息的额外好处;虽然索引 65 指向元素 1,但我仍然保留索引在逻辑上为 65 的信息(这证明非常有用)。

我还想补充一点,当索引增长到 3456237(缓冲区中的地址 13)时,这与索引增长到 3 时一样有效。

我知道我迟到了,我什至不确定我是如何找到这个问题的 :-) 希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-10
    • 1970-01-01
    • 2016-09-21
    • 2017-12-07
    相关资源
    最近更新 更多