使用unsigned模数的数组环绕

时间:2010-10-18 12:52:05

标签: c++ c arrays random circular-buffer

我正在尝试为一些最大值的整数实现lagged Fibonacci伪随机数生成器。它维护一个值数组

int values[SIZE] = { /* 55 seed values */ };

并使用以下函数返回下一个值

unsigned lagfib()
{
    static unsigned idx = 0;
    int r = values[idx];

    /* The following does not work: */
    values[idx] = (values[(idx-24) % SIZE] + values[(idx-55) % SIZE])
                 % MAX_VALUE;
    idx = (idx+1) % SIZE;
    return r;
}

实际上,values应该是一个始终满的简单环形缓冲区。减法和模数应将索引包装到数组的末尾。 SIZE应始终至少为55,但我希望将其四舍五入到64以加快模数。

但显然,我的模数计算错了,我不知道如何修复它们。将索引类型更改为int并不会改善事情。

(PS:是的,static数据样式不好,但我希望这对C和C ++程序员都是可读的,因为它适用于这两种语言。)

3 个答案:

答案 0 :(得分:3)

让我们idx = 0SIZE = 64

(idx-24) % SIZE将是一个非常大的值(对于32位int 4294967272),因为idx是无符号的,因此它是无效的索引。

要获得圆形效果,您应该在 之前添加SIZE 模数:

(idx-24+SIZE) % SIZE将为(0-24+64)%64,评估为40

答案 1 :(得分:2)

如果是idx小于24,您将转到数字范围unsigned int的另一端。 55不是例如55的除数。 2 ^ 32,所以这不会给你正确的结果。

我可以看到两个选项:

  • 维护三个单独的idx变量,分别偏移24和55。
  • 例如(idx - 24 + SIZE) % SIZE

实际上,我会选择第一个选项,并通过重写增量来完全避免模数:

idx = ((SIZE-1) == idx) ? 0 : (idx+1);

这可能比计算模数更快。

答案 2 :(得分:0)

您正在使用负索引访问值。例如:

-24 % 55 == -24

所以你需要一些逻辑来包装到数组的末尾。 C / C ++不会为你做这件事。