C++ 无符号模环绕数组

C++ 无符号模环绕数组,c++,c,arrays,random,circular-buffer,C++,C,Arrays,Random,Circular Buffer,我正在尝试实现一个最大整数的伪随机数生成器。它维护一个值数组 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] +

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

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;
}
实际上,
应该是一个总是满的简单环形缓冲区。减法和模运算应该将索引环绕到数组的末尾
SIZE
应始终至少为55,但我想将其四舍五入到64以加快模运算速度

但很明显,我的模计算错了,我不知道如何修正它们。将索引类型更改为
int
并不能改善情况


(PS:是的,代码> static < /COD>数据是坏的样式,但我希望这对于C和C++程序员都是可读的,因为它属于两种语言)。< /P> < P>如果例如代码> IDX 小于24,你将被打包到代码的编号范围的另一端。55不是除数,例如2^32,因此这不会给出正确的结果

我可以看到两种选择:

  • 维护三个独立的
    idx
    变量,分别偏移24和55
  • 执行例如
    (idx-24+尺寸)%SIZE
实际上,我会选择第一个选项,并通过将增量重写为以下内容来完全避免模:

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

这可能比计算模要快得多。

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

-24 % 55 == -24

因此,需要一些逻辑来结束数组。C/C++不会为您这样做。

让我们采用
idx=0
SIZE=64

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

要获得圆形效果,应在取模数之前添加
尺寸


(idx-24+SIZE)%SIZE
将是
(0-24+64)%64
,其计算结果为
40

+1并被接受,但我假设模64被编译为位掩码运算。我真的应该刷新我的模算术。@larsmans:哦,那么你的代码中确实有
SIZE==64
,您是否考虑到种子值需要“反向”排列?返回到
SIZE=55
,并注意到
idx+55-SIZE
现在是
idx
,因此我只需要两个索引。谢谢!为什么是<代码>静态< /代码>数据坏样式(在C中,或者仅仅是C++)?它也是坏的样式,因为它导致不可重入代码。@ EndoList:因为它使代码不线程安全。@拉斯曼:为什么那么糟糕?或者更确切地说,什么时候是糟糕的?如果语言结构总是不好的话,它就不会存在,是吗?@endolith:我倾向于以线程安全的方式编写代码,除非我在做这样的实验。是的,
static
有一个用途,就是这样,但只有这是一个一次性的程序。