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

问题描述 投票:32回答:17
srand(time(null));

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

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

c random
17个回答
57
投票
rand() % (max_number + 1 - minimum_number) + minimum_number

所以,对于0-65:

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

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

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


1
投票

double RAND(double min, double max) { return (double)rand()/(double)RAND_MAX * (max - min) + min; } 将返回介于0和RAND_MAX之间的数字,至少为32767。

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

rand()

为了更准确,int value = rand() % 66; // 0-65 。它讨论了为什么模数不一定好(坏分布,特别是在高端),并提供各种选项。


1
投票

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

check out this article

但是,(aMax - aMin)有可能溢出。例如。 aMax = 1,aMin = -DBL_MAX。更安全的方法是这样写:

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

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

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

0
投票

我认为以下是半正确的。自从我触及C以来已经有一段时间了。这个想法是使用除法,因为模数并不总是给出随机结果。我向RAND_MAX添加了1,因为有许多可能的值来自rand,包括0.由于范围也是0,所以我也加了1。我认为数学排列正确,避免整数数学问题。

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

0
投票

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

使用像#define MK_DIVISOR(max) ((int)((unsigned int)RAND_MAX+1/(max+1))) num = rand()/MK_DIVISOR(65); 或其他高质量prng那样的其他prng

然后就去模数。


0
投票

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

mod http://en.wikipedia.org/wiki/Mersenne_twister操作将始终执行完全除法,因此产生小于除数的余数。

x%y = x - (和* floor((x / y)))

具有注释的随机范围查找功能的示例:

%

另外一个有趣的属性如上:

x%y = x,如果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);
}

0
投票
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()

0
投票

只使用rand()会在多次运行程序时给出相同的随机数。即,当您第一次运行程序时,它会生成随机数x,y和z。如果再次运行程序,它将产生与我观察到的相同的x,y和z数字。

我发现每次都保持独特的解决方案是使用srand()

这是附加代码,

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()%(max_number + 1 - minimum_number)+ minimum_number

希望能帮助到你!


-2
投票

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

例如:

#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.

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


16
投票

检查一下

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

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

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

9
投票

你可以用这个:

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

来自:

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

Q: How can I get random integers in a certain range?

A: The obvious way,

rand() % N        /* POOR */

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

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

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

rand() / (RAND_MAX / N + 1)

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

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

所有这些方法显然需要知道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;

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

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

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

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

(int)(drand48() * N)

Additional links

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

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


6
投票

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

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

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

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

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

rand()  freq. rand() % 2
0       1/3   0
1       1/3   1
2       1/3   0

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

阿特伍德先生讨论了这个问题in this Coding Horror Article


5
投票

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

Java qazxsw poi类中使用了一个非常巧妙和良好的解决方案:

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; } 循环的条件,它拒绝数字范围内的数字,否则会导致分布不均匀。


3
投票
while

2
投票

如果你不过分关心低阶位的“随机性”,只需rand()%HI_VAL。

也:

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

2
投票

天真的方式是:

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

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

要解释为什么它不是很一致,请考虑这个非常简单的例子: 假设RAND_MAX为4,你想要一个0-2的数字。您可以获得的可能值显示在此表中:

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

看到问题?如果您的最大值不是RAND_MAX的偶数除数,则您更有可能选择较小的值。但是,由于RAND_MAX通常为32767,因此偏差可能很小,足以在大多数情况下逃脱。

有各种方法可以解决这个问题;请参阅rand() | rand() % 3 ---------+------------ 0 | 0 1 | 1 2 | 2 3 | 0 ,了解Java的here如何处理它。


2
投票

更新为不使用#define

Random
© www.soinside.com 2019 - 2024. All rights reserved.