【问题标题】:Array wraparound with modulo of unsigned以无符号为模的数组环绕
【发布时间】:2011-04-26 22:27:48
【问题描述】:

我正在尝试实现一个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++ 程序员都可读,因为它适用于两种语言。)

【问题讨论】:

  • 为什么 static 数据风格不好(在 C 中,或者您的意思是仅 C++)?
  • 在 C 中这也是一种糟糕的风格,因为它会导致代码不可重入。
  • @endolith:因为它使代码非线程安全。
  • @larsmans:为什么这么糟糕?或者更确切地说,什么时候不好?如果语言结构总是不好,就不会存在,不是吗?
  • @endolith:我倾向于以线程安全的方式编写代码,除非我在这种情况下进行实验。所以是的,static 有一个用途,就是这样,但这只是一个一次性程序。

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


【解决方案1】:

让我们来看看idx = 0 和SIZE = 64。

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

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

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

【讨论】:

    【解决方案2】:

    您正在访问具有负索引的值。例如:

    -24 % 55 == -24
    

    所以你需要一些逻辑来环绕到数组的末尾。 C/C++ 不会为您执行此操作。

    【讨论】:

      【解决方案3】:

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

      我可以看到两个选项:

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

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

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

      这可能比计算模数要快。

      【讨论】:

      • +1 并被接受,但我假设模 64 被编译为位掩码操作。我真的应该刷新我的模运算。
      • @larsmans:哦,你的代码中确实有SIZE == 64?
      • @larsmans:顺便说一句,您是否考虑到您的种子值需要以“反向”顺序排列?
      • 回到SIZE=55,注意到idx + 55 - SIZE现在是idx,所以我只需要两个索引。非常感谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 2011-01-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多