关于随机整数生成的标准(C)

时间:2015-04-08 09:05:48

标签: c random

我正在运行一系列物理模拟,其中我需要随机数。我正在使用C ++中的标准rand()函数。

所以它的工作原理如下:首先,我为一组不同的1/(1+exp(a))预先计算了a形式的一堆概率。它们是由double库中的exp函数返回的类型math,然后事情必定发生在那些概率中,只有两个,所以我生成一个随机的数均匀分布在0和1之间,并与那些预先计算的概率进行比较。为此,我使用了:

double p = double(rand()%101)/100.0;

所以我给出了01之间的随机值。这并没有产生正确的物理结果。我试过这个:

double p = double(rand()%1000001)/1000000.0;

这很有效。我真的不明白为什么所以我想要一些关于如何做的标准。我的直觉告诉我,如果我做了

double p = double(rand()%(N+1))/double(N);

N足够大,使得最小的分割(1/N)远小于最小概率1/1+exp(a),那么我将得到逼真的随机数。

我想理解为什么。

3 个答案:

答案 0 :(得分:1)

rand()返回0到RAND_MAX之间的随机数。

因此你需要这个:

double p = double(rand() % RAND_MAX) / double(RAND_MAX);

同时运行此代码段,您就会明白:

  int i;

  for (i = 1; i < 30; i++)
  {
      int rnd = rand();
      double p0 = double(rnd % 101) / 100.0;
      double p1 = double(rnd % 1000001) / 1000000.0;
      printf ("%d\t%f\t%f\n", rnd, p0, p1);
  }

  for (i = 1; i < 30; i++)
  {
      int rnd = rand();
      double p0 = double(rnd) / double(RAND_MAX);
      printf ("%d\t%f\n", rnd, p0);
  }

答案 1 :(得分:1)

你有很多问题。

  1. rand()根本不是随机的。在几乎所有的操作系​​统上,它都会返回分布严重,可怕的偏差数字。实际上很难找到一个好的随机数生成器,但我可以向你保证rand()将是你能找到的最差的。

  2. rand() % N给出了有偏见的分布。想想鸽笼原理。让我们简化它,假设rand返回数字[0,7]并且你的N是6. 0到5映射到0到5,6映射到0和7映射到1,意味着0和1是两次很可能会出来。

  3. 在分割之前将数字转换为双精度不会从2中删除偏差,它只会使其不太明显。无论你做什么转换,鸽子原则都适用。

  4. 将分布均匀的随机数从整数转换为float / double比看起来更难。简单划分忽略了浮点数学如何工作的问题。

  5. 我无法帮助你1,你需要做研究。查看随机数库的网络。如果你想要一些非常随机和不可预测的东西,你需要寻找加密随机库。如果你想要一个可重复但好的随机数Mersenne Twister应该足够好了。但你需要在这里做研究。

    对于2和3,有标准解决方案。您正在将一组从M个元素映射到N个元素,而rand % N仅在iff N&lt; M和N和M共享主要因素。因为在大多数系统中,M将是2的幂,这意味着N也必须是2的幂。因此,假设M是2的幂,算法是:找到高于或等于N的2的最近幂,让我们称之为P.生成randomness_source() % P。如果数字高于N,请将其丢弃并重试。这是唯一安全的方法。比你和我更聪明的人在这个问题上花费了多年时间,没有更好的方法来消除这种偏见。

    对于4,你可以忽略这个问题并且只是划分,在绝大多数情况下,这应该是足够好的。如果你真的想研究这个问题,我已经完成了一些工作并发布了代码on github.在那里,我将介绍浮点数如何工作的基本原理以及它与生成随机数的关系。

答案 2 :(得分:0)

// produces pseudorandom bits.  These are NOT crypto quality bits.  Has the same underlying unpredictability as uncooked
// rand() output.  It buffers rand() bits to produce a more convenient zero-to-the-argument range including negative
// arguments, corrects for the toward-zero bias of the modular construction I'd be using otherwise, eliminates the
// RAND_MAX range limitation, (use INT64_MAX instead) and effectively obscures biases and sequence telltales due to
// annoyingly bad rand libraries.  It does not correct these biases; anyone tracking the arguments and outputs has
// enough information to reconstruct the rand() output and detect them.  But it makes the relationships drastically more complicated.

// needs stdint, stdlib.

int64_t privaterandom(int64_t range, int reset){
    static uint64_t state = 0;
    int64_t retval;
    if (reset != 0){
       srand((unsigned int)range);
       state = (uint64_t)range;
    }
    if (range == 0) return (0);
    if (range < 0) return -privaterandom(-range, 0);
    if (range > UINT64_MAX/0xFFFFFFFF){
       retval = (privaterandom(range/0xFFFFFFFF, 0) * 0xFFFFFFFF); // order of operations matters
       return (retval + privaterandom(0xFFFFFFFF, 0));
    }
    while (state < UINT64_MAX / 0xFF){
       state *= RAND_MAX;
       state += rand();
    }
    retval = (state % range);
    // makes "pigeonhole" bias alternate unpredictably between toward-even and toward-odd
    if ((state/range > (state - (retval) )/ range) && state % 2 == 0) retval++; 
    state /= range;
    return retval;
}
int64_t Random(int64_t range){ return (privaterandom(range, 0));}
int64_t Random_Init(int64_t seed){return (privaterandom(seed, 1));}