如何从 rand()得到一个特定的数值范围?

srand(time(null));


printf("%d", rand());

给出一个高范围的随机数(0-32000左右) ,但我只需要大约0-63或0-127,虽然我不知道如何去做。有人帮忙吗?

264182 次浏览

如果你不太在意低阶比特的“随机性”,那就用 rand ()% HI _ VAL。

另外:

(double)rand() / (double)RAND_MAX;  // lazy way to get [0.0, 1.0)

最天真的做法是:

int myRand = rand() % 66; // for 0-65

这可能是一个非常轻微的非均匀分布(取决于您的最大值) ,但它非常接近。

为了解释为什么它不是完全统一的,考虑这个非常简单的例子:
假设 RAND _ MAX 是4,并且您需要一个从0到2的数字。您可以得到的可能值如下表所示:

rand()   |  rand() % 3
---------+------------
0        |  0
1        |  1
2        |  2
3        |  0

看到问题了吗?如果您的最大值不是 RAND _ MAX 的偶数因子,那么您更有可能选择较小的值。然而,由于 RAND _ MAX 通常是32767,所以偏差可能很小,在大多数情况下不会受到影响。

有多种方法可以解决这个问题; 有关 Java 的 Random如何处理这个问题的解释,请参阅 给你

RAND () 将返回0和 RAND _ MAX 之间的数字,这至少是32767。

如果你想得到一个范围内的数字,你可以只使用模。

int value = rand() % 66; // 0-65

为了更准确,看看这篇文章。它讨论了为什么模块不一定是好的(坏的发行版,特别是在高端) ,并提供了各种选项。

rand() % (max_number + 1 - minimum_number) + minimum_number

所以,0-65:

rand() % (65 + 1 - 0) + 0

(显然你可以把0去掉,但它是为了完整性而存在的)。

请注意,这将稍微偏离随机性,但可能没有什么需要担心的,如果你没有做一些特别敏感的事情。

更新为不使用 # Definition

double RAND(double min, double max)
{
return (double)rand()/(double)RAND_MAX * (max - min) + min;
}

采取模的结果,作为其他海报已断言,将给你的东西,是 差不多随机,但不完全如此。

考虑这个极端的例子,假设您想模拟掷硬币,返回0或1。你可以这样做:

isHeads = ( rand() % 2 ) == 1;

看起来没什么大碍,对吧?假设 RAND _ MAX 仅为3。当然它要高得多,但是这里的要点是,当你使用一个不能均匀除以 RAND _ MAX 的模时,存在一个偏差。如果你想要高质量的随机数,你会遇到一个问题。

想想我的例子,可能的结果是:

Rand () 频率。 兰特()% 2
0 1/3 0
1 1/3 1
2 1/3 0

因此,“反面”出现的频率是“正面”的两倍!

阿特伍德先生讨论这件事

我觉得下面这句话有点道理。我已经很久没碰过 C 了。这个想法是使用除法,因为模并不总是给出随机结果。我将1添加到 RAND _ MAX,因为有很多可能的值来自于 RAND,包括0。由于范围也是0包含,我在那里也加了1。我认为数学的安排是正确的,避免整数数学问题。

#define MK_DIVISOR(max) ((int)((unsigned int)RAND_MAX+1/(max+1)))


num = rand()/MK_DIVISOR(65);

看这里

Http://c-faq.com/lib/randrange.html

对于这些技术中的任何一种,如果有必要,可以直接移动范围; 可以使用类似下面的代码生成范围[ M,N ]中的数字

M + rand() / (RAND_MAX / (N - M + 1) + 1)
double scale = 1.0 / ((double) RAND_MAX + 1.0);
int min, max;
...
rval = (int)(rand() * scale * (max - min + 1) + min);

正如其他人指出的那样,简单地使用模数会使单个数字的概率发生倾斜,因此更倾向于使用较小的数字。

Java 的 java.util.Random类中使用了一个非常巧妙和好的解决方案:

public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");


if ((n & -n) == n)  // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);


int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}

我花了一段时间才明白它为什么有效,我把它留给读者作为练习,但它是一个相当简洁的解决方案,将确保数字具有相同的概率。

这段代码的重要部分是 while循环的条件,它拒绝掉落在数字范围内的数字,否则会导致不均匀的分布。

如果你关心随机数的质量,不要使用 rand ()

使用一些其他 prng 像 http://en.wikipedia.org/wiki/Mersenne_twister或其他高品质的 prng 的在那里

那就用模数吧。

你可以用这个:

int random(int min, int max){
return min + rand() / (RAND_MAX / (max - min + 1) + 1);
}

来自:

常见问题清单 · 问题13.16

问: 我怎样才能得到一定范围内的随机整数?

答: 很明显,

rand() % N        /* POOR */

(试图将数字从0返回到 N-1)很糟糕,因为 许多随机数发生器的低阶比特是令人苦恼的 一个更好的方法是这样的

(int)((double)rand() / ((double)RAND_MAX + 1) * N)

如果不想使用浮点数,另一种方法是

rand() / (RAND_MAX / N + 1)

如果你只需要做一些概率为1/N 的事情,你可以使用

if(rand() < (RAND_MAX+1u) / N)

显然,所有这些方法都需要知道 RAND _ MAX (ANSI # 在 < stdlib.h > 中定义) ,并假设 N 比 RAND _ MAX 小得多。当 N 接近 RAND _ MAX 时,如果随机数的范围 生成器不是 N 的倍数(即如果(RAND _ MAX + 1)% N! = 0) ,则所有 这些方法分解: 一些输出出现的频率超过 (使用浮点数没有帮助,问题是兰特 返回 RAND _ MAX + 1不同的值,这些值不能总是均匀的 如果这是一个问题,那么唯一的问题就是 可以多次调用 rand,丢弃某些值:

unsigned int x = (RAND_MAX + 1u) / N;
unsigned int y = x * N;
unsigned int r;
do {
r = rand();
} while(r >= y);
return r / x;

对于这些技术中的任何一种,改变范围都很简单, 如果需要,可以使用以下命令生成范围[ M,N ]内的数字 比如

M + rand() / (RAND_MAX / (N - M + 1) + 1)

(注意,顺便说一下,RAND _ MAX 是一个 不变,它告诉您 函数的固定范围是。不能设置 RAND _ MAX 转换为其他值,并且没有办法请求该 Rand 其他范围内的返回值)

如果你从一个随机数生成器开始 0到1之间的浮点值(例如 在问题 13.15或者问题 drand48中提到的 PMrand 13.21 ) ,要得到从0到 N-1的整数,所需要做的就是 将发电机的输出乘以 N:

(int)(drand48() * N)

附加链接

参考文献: K & R 2 Sec. 7.8.7 p. 168
PCS 第11节第172页

引自: http://c-faq.com/lib/randrange.html

只是为了给现有的答案添加一些额外的细节。

Mod %操作将始终执行一个完整的除法,因此产生的余数小于除数。

X% y = x-(y * 地板((x/y)))

一个带注释的随机范围查找函数示例:

uint32_t rand_range(uint32_t n, uint32_t m) {
// size of range, inclusive
const uint32_t length_of_range = m - n + 1;


// add n so that we don't return a number below our range
return (uint32_t)(rand() % length_of_range + n);
}

另一个有趣的属性如上所述:

X% y = x,如果 x < y

const uint32_t value = rand_range(1, RAND_MAX); // results in rand() % RAND_MAX + 1
// TRUE for all x = RAND_MAX, where x is the result of rand()
assert(value == RAND_MAX);
result of rand()
2 cents (ok 4 cents):


n = rand()
x = result
l = limit


n/RAND_MAX = x/l


Refactor:


(l/1)*(n/RAND_MAX) = (x/l)*(l/1)


Gives:


x = l*n/RAND_MAX


int randn(int limit)


{


return limit*rand()/RAND_MAX;


}


int i;


for (i = 0; i < 100; i++) {


printf("%d ", randn(10));
if (!(i % 16)) printf("\n");


}


> test
0
5 1 8 5 4 3 8 8 7 1 8 7 5 3 0 0
3 1 1 9 4 1 0 0 3 5 5 6 6 1 6 4
3 0 6 7 8 5 3 8 7 9 9 5 1 4 2 8
2 7 8 9 9 6 3 2 2 8 0 3 0 6 0 0
9 2 2 5 6 8 7 4 2 7 4 4 9 7 1 5
3 7 6 5 3 1 2 4 8 5 9 7 3 1 6 4
0 6 5

只要使用 rand () ,在多次运行程序时就会得到相同的随机数。也就是说,当你第一次运行你的程序时,它会产生随机数 x,y 和 z。如果你再次运行这个程序,它会产生相同的 x,y 和 z 值,就像我观察到的那样。

我发现的解决方案是每次使用 srand ()来保持它的唯一性

这是附加代码,

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


time_t t;
srand((unsigned) time(&t));
int rand_number = rand() % (65 + 1 - 0) + 0 //i.e Random numbers in range 0-65.

要设置范围,可以使用公式: rand ()% (max _ number + 1-max _ number) + limit _ number

希望能有帮助!

这个答案并不关注随机性,而是关注算术顺序。 为了得到一个范围内的数字,通常我们可以这样做:

// the range is between [aMin, aMax]
double f = (double)rand() / RAND_MAX;
double result = aMin + f * (aMax - aMin);

但是,存在溢出的可能性(aMax-aMin)。例如 aMax = 1,aMin =-DBL _ MAX。更安全的方法是这样写:

// the range is between [aMin, aMax]
double f = (double)rand() / RAND_MAX;
double result = aMin - f * aMin + f * aMax;

基于这个概念,这样的事情可能会导致一个问题。

rand() % (max_number + 1 - minimum_number) + minimum_number
// 1. max_number + 1 might overflow
// 2. max_number + 1 - min_number might overflow

您可以通过在 rand 函数前面添加% 来更改它,以便更改为代码

例如:

rand() % 50

将给你一个50范围内的随机数。对你来说,用63或127代替50

如果您决定使用 %,则需要进行重滚以获得正确的分布。大部分时间都可以跳过回滚,因为你只需要避免掉进最后一个桶里的数字:

int rand_less_than(int max) {
int last_bucket_min = RAND_MAX - RAND_MAX % max;
int value;
do {
value = rand();
} while (last_bucket_min <= value);


return value % max;
}

有关图解的说明,请参阅 @ JarosrawPawlak的文章: 基于模的随机数发生器

对于 RAND_MAX < max,您需要展开生成器: 将随机范围从1-5扩展到1-7