如何从rand()获取特定范围的数字?

akw*_*way 33 c random

srand(time(null));

printf("%d", rand());
Run Code Online (Sandbox Code Playgroud)

给出一个高范围的随机数(0-32000ish),但我只需要大约0-63或0-127,但我不知道如何去做.有帮助吗?

Tyl*_*nry 61

rand() % (max_number + 1 - minimum_number) + minimum_number
Run Code Online (Sandbox Code Playgroud)

所以,对于0-65:

rand() % (65 + 1 - 0) + 0
Run Code Online (Sandbox Code Playgroud)

(显然你可以将0关闭,但它是完整的).

请注意,这会略微偏向随机性,但如果您没有做一些特别敏感的事情,可能没有什么可担心的.

  • Modulo依赖于低阶位,它不像高阶位那样随机.转换为float和multiply效果更好. (5认同)
  • number_of_numbers + 1.您的代码将给出0-64. (3认同)
  • 不,它仍然是number_of_numbers,但是包含范围0-65中的数字的数量是66而不是65. (2认同)
  • 低阶位不太随机。此外,number_of_numbers 的值越小,偏差越明显。与 RAND_MAX 无关。例如,如果 `number_of_numbers` 为 2,您将看到最低位的偏差。 (2认同)

小智 16

检查一下

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

对于这些技术中的任何一种,如果需要,可以直接改变范围; [M,N]范围内的数字可以用类似的东西生成

M + rand() / (RAND_MAX / (N - M + 1) + 1)
Run Code Online (Sandbox Code Playgroud)

  • 你希望这些1中的一个为1.0以确保浮动,否则你只需要0 + M ...... (8认同)
  • @BrianPostow 不,你绝对不*不*想要一个浮点数。计算是正确的,因为它站在那里,并在“M”和“N”(含)之间产生随机数。只要 NM 与 RAND_MAX 相比较小,分布就非常均匀。阅读链接的文章。 (2认同)

Vit*_*.us 10

你可以用这个:

int random(int min, int max){
   return min + rand() / (RAND_MAX / (max - min + 1) + 1);
}
Run Code Online (Sandbox Code Playgroud)

来自:

comp.lang.c常见问题列表·问题13.16

问:如何在一定范围内获得随机整数?

答:显而易见的方式,

rand() % N        /* POOR */
Run Code Online (Sandbox Code Playgroud)

(试图将数字从0返回到N-1)很差,因为许多随机数发生器的低位比特是令人沮丧的非随机的.(参见问题13.18.)更好的方法是类似的

(int)((double)rand() / ((double)RAND_MAX + 1) * N)
Run Code Online (Sandbox Code Playgroud)

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

rand() / (RAND_MAX / N + 1)
Run Code Online (Sandbox Code Playgroud)

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

if(rand() < (RAND_MAX+1u) / N)
Run Code Online (Sandbox Code Playgroud)

所有这些方法显然需要知道RAND_MAX(<stdlib.h>中的ANSI #defines),并假设N远小于RAND_MAX.当N接近RAND_MAX时,如果随机数发生器的范围不是N的倍数(即,如果(RAND_MAX + 1)%N!= 0),则所有这些方法都会中断:某些输出比其他.(使用浮点没有帮助;问题是rand返回RAND_MAX + 1个不同的值,这些值不能总是均匀地分配到N个桶中.)如果这是一个问题,你唯一能做的就是调用rand multiple次,丢弃某些值:

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

对于这些技术中的任何一种,如果需要,可以直接改变范围; [M,N]范围内的数字可以用类似的东西生成

M + rand() / (RAND_MAX / (N - M + 1) + 1)
Run Code Online (Sandbox Code Playgroud)

(顺便说一下,R​​AND_MAX是一个常数,告诉你C库rand函数的固定范围是什么.你不能将RAND_MAX设置为其他值,并且无法 在其他范围内请求rand返回数字.)

如果你从一个随机数生成器开始,它返回0到1之间的浮点值(例如问题13.15中提到的PMrand的最后一个版本 ,或问题13.21中的 drand48 ),你需要做的就是从中获取整数0到N-1将该生成器的输出乘以N:

(int)(drand48() * N)
Run Code Online (Sandbox Code Playgroud)

其他链接

参考文献:K&R2 Sec.7.8.7 p.168
PCS Sec.11 p.172

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


Mic*_*ers 6

天真的方法是:

int myRand = rand() % 66; // for 0-65
Run Code Online (Sandbox Code Playgroud)

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

要解释为什么它不是很统一,请考虑这个非常简化的示例:
假设 RAND_MAX 是 4,并且您想要一个 0-2 之间的数字。您可以获得的可能值如下表所示:

rand()   |  rand() % 3
---------+------------
0        |  0
1        |  1
2        |  2
3        |  0
Run Code Online (Sandbox Code Playgroud)

看到问题了吗?如果您的最大值不是 RAND_MAX 的偶数除数,您将更有可能选择较小的值。但是,由于 RAND_MAX 通常为 32767,因此偏差可能小到足以满足大多数目的。

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


Bob*_*man 6

取其结果的模数,正如其他海报所宣称的那样,会给你一些几乎随机的东西,但并不完美.

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

isHeads = ( rand() % 2 ) == 1;
Run Code Online (Sandbox Code Playgroud)

看起来很无害,对吧?假设RAND_MAX只有3.它当然要高得多,但这里的要点是当你使用一个不均匀划分RAND_MAX的模数时存在偏差.如果你想要高质量的随机数,你就会遇到问题.

考虑我的例子.可能的结果是:

rand()  freq. rand() % 2
0       1/3   0
1       1/3   1
2       1/3   0
Run Code Online (Sandbox Code Playgroud)

因此,"尾巴"的发生频率是"头"的两倍!

阿特伍德先生在这篇编码恐怖文章中讨论了这个问题

  • 那么更好的解决方案是......? (3认同)

Ree*_*sey 5

rand()将返回 0 到 RAND_MAX 之间的数字,至少是 32767。

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

int value = rand() % 66; // 0-65
Run Code Online (Sandbox Code Playgroud)

为了更准确,请查看这篇文章。它讨论了为什么模不一定是好的(不好的分布,特别是在高端),并提供了各种选择。


Mar*_*iec 5

更新为不使用 #define

double RAND(double min, double max)
{
    return (double)rand()/(double)RAND_MAX * (max - min) + min;
}
Run Code Online (Sandbox Code Playgroud)

  • 坏主意,由于宏的所有警告。该宏在许多情况下都会失败,因为参数没有正确加括号,即使你这样做正确,它仍然会计算 min 参数两次,如果 min 是一个有副作用的函数,这将是糟糕的。 (2认同)

Joh*_*ode 5

double scale = 1.0 / ((double) RAND_MAX + 1.0);
int min, max;
...
rval = (int)(rand() * scale * (max - min + 1) + min);
Run Code Online (Sandbox Code Playgroud)


Joe*_*oey 5

正如其他人所指出的那样,简单地使用模数会使个别数字的概率产生偏差,因此较小的数字是首选.

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;
}
Run Code Online (Sandbox Code Playgroud)

我花了一段时间才明白它为什么会起作用,我把它留作读者的练习,但它是一个非常简洁的解决方案,可确保数字具有相同的概率.

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

  • 这是一个旧答案,很抱歉打扰您,但是这个答案有点奇怪,因为问题是用 C 标记的,如果您能花时间添加 C 等效代码的示例,那就太好了。例如,什么是“next()”?[此处](https://rextester.com/ICTIC19273) 仍然需要用 C 等效函数替换 `next()` 的命题。 (2认同)

gen*_*ult 2

如果您不太关心低位的“随机性”,只需 rand() % HI_VAL 即可。

还:

(double)rand() / (double)RAND_MAX;  // lazy way to get [0.0, 1.0)
Run Code Online (Sandbox Code Playgroud)

  • 提示:任何时候您向伪随机数生成器“添加”随机性时,您很可能会无意中减去它……或者至少不会更改它。 (2认同)