如何从C的整个int范围生成一个随机数?

时间:2016-02-18 19:02:14

标签: c random

unsigned const number = minimum + (rand() % (maximum - minimum + 1))

我知道如何(轻松)生成0到100范围内的随机数。但int全范围中的随机数呢(假设{ {1}}),即sizeof(int) == 4INT_MIN,包括哪个?

我不需要这个用于加密等,但是大致均匀的分布会很好,我需要很多这些数字。

我目前使用的方法是生成0到255(含)范围内的4个随机数,并进行一些混乱的转换和位操作。我想知道是否有更好的方式。

3 个答案:

答案 0 :(得分:4)

在我的系统RAND_MAX上是32767,即15位。因此,对于32位unsigned,只需调用三次并移位,或者屏蔽等。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void){
    unsigned rando, i;
    srand((unsigned)time(NULL));
    for (i = 0; i < 3; i++) {
        rando = ((unsigned)rand() << 17) | ((unsigned)rand() << 2) | ((unsigned)rand() & 3);
        printf("%u\n", rando);
    }
    return 0;
}

节目输出:

3294784390
3748022412
4088204778

答案 1 :(得分:1)

作为参考,我正在添加我一直在使用的内容:

int random_int(void) {
  assert(sizeof(unsigned int) == sizeof(int));
  unsigned int accum = 0;
  size_t i = 0;
  for (; i < sizeof(int); ++i) {
    i <<= 8;
    i |= rand() & 0x100;
  }
  // Attention: Implementation defined!
  return (int) accum;
}

但我更喜欢Weather Vane的解决方案,因为它使用较少的rand()次调用,从而更多地利用了它产生的(希望是好的)分布。

答案 2 :(得分:0)

我们应该能够通过累积足够的位来填充给定类型,无论rand()的范围是什么,或者我们正在寻找什么尺寸的结果,我们都应该做一些有用的事情:

// can be any unsigned type.
typedef uint32_t uint_type;
#define RAND_UINT_MAX ((uint_type) -1)

uint_type rand_uint(void)
{
    // these are all constant and factor is likely a power of two.
    // therefore, the compiler has enough information to unroll
    // the loop and can use an immediate form shl in-place of mul.
    uint_type factor = (uint_type) RAND_MAX + 1;
    uint_type factor_to_k = 1;
    uint_type cutoff = factor ? RAND_UINT_MAX / factor : 0;
    uint_type result = 0;

    while ( 1 ) {
        result += rand() * factor_to_k;
        if (factor_to_k <= cutoff)
            factor_to_k *= factor;
        else
            return result;
    }
}

注意:使填充所有位所需的最小呼叫数为rand()

让我们verify给出统一的分布。

此时我们可以将rand_uint()的结果转换为类型 int 并完成,但是在指定范围内输出更有用。问题是:当操作数类型为 int 时,我们如何到达INT_MAX

好吧......我们做不到。我们需要使用范围更大的类型:

int uniform_int_distribution(int min, int max)
{
    // [0,1) -> [min,max]
    double canonical = rand_uint() / (RAND_UINT_MAX + 1.0);
    return floor(canonical * (1.0 + max - min) + min);
}

作为最后一点,可能值得用类型 double 来实现随机函数,即为DBL_MANT_DIG积累足够的位并返回范围< EM> [0,1)。实际上这就是std::generate_canonical的作用。