39

以下代码每秒输出一个随机数:

int main ()
{
    srand(time(NULL)); // Seeds number generator with execution time.

    while (true)
    {
        int rawRand = rand();

        std::cout << rawRand << std::endl;

        sleep(1);
    }
}

我如何缩小这些数字的大小,使它们始终在 0-100 的范围内?

4

9 回答 9

84

如果您正在使用 C++ 并且关心良好的分布,您可以使用TR1 C++11 <random>

#include <random>

std::random_device rseed;
std::mt19937 rgen(rseed()); // mersenne_twister
std::uniform_int_distribution<int> idist(0,100); // [0,100]

std::cout << idist(rgen) << std::endl;
于 2010-11-16T17:02:10.590 回答
32

到目前为止发布的所有示例实际上都给出了分布不均的结果。经常执行代码并创建统计数据以查看值如何倾斜。

在任何范围 [0, N ] 中生成真正均匀随机数分布的更好方法如下(假设实际上遵循均匀分布,这远非显而易见):rand

unsigned result;
do {
    result = rand();
} while (result > N);

当然,这种方法很慢,但它确实产生了良好的分布。一个更聪明的方法是找到小于的最大NRAND_MAX倍数并将其用作上限。在那之后,人们可以安全地服用result % (N + 1)

有关为什么朴素模数方法不好以及为什么上述方法更好的解释,请参阅 Julienne 关于使用的优秀文章rand

于 2010-11-16T15:55:01.793 回答
27

int rawRand = rand() % 101;

见(更多细节):

rand - C++ 参考

其他人还指出,这不会为您提供尽可能好的随机数分布。如果这种事情在您的代码中很重要,您将不得不这样做:

int rawRand = (rand() * 1.0 / RAND_MAX) * 100;

编辑

三年过去了,我正在编辑。正如其他人提到的,rand()有很多问题。显然,当未来有更好的选择时,我不推荐使用它。您可以在此处阅读有关详细信息和建议的所有信息:

rand() 被认为是有害的 | GoingNative 2013

于 2010-11-16T15:49:24.250 回答
6

你可以做

cout << rawRand % 100 << endl; // Outputs between 0 and 99

cout << rawRand % 101 << endl; // outputs between 0 and 100

对于投反对票的人;请注意,在最初发布此内容一分钟后,我留下了评论:

来自http://www.cplusplus.com/reference/clibrary/cstdlib/rand “请注意,尽管此模运算不会在跨度中生成真正均匀分布的随机数(因为在大多数情况下,较小的数字更有可能),但它通常是短跨度的一个很好的近似值。”

使用 64 位整数并使用 100 个数字作为输出,数字 0-16 用 1.00000000000000000455 % 的数字表示(与 1% 同分布的相对精度约为 10 -18),而数字 17-99 则表示0.99999999999999999913 % 的数字。是的,不是完全分布,但对于小跨度来说是一个非常好的近似值。

另请注意,OP 在哪里要求相同分布的数字?据我们所知,这些被用于小偏差无关紧要的目的(例如,除了密码学之外的任何东西——如果他们使用数字进行密码学,这个问题对于他们来说太天真了,无法编写自己的密码学)。

编辑- 对于真正关心随机数均匀分布的人,以下代码有效。请注意,这不一定像 64 位随机整数那样是最佳的,它需要rand()每 10^18 次调用两次调用一次。

unsigned N = 100; // want numbers 0-99
unsigned long randTruncation = (RAND_MAX / N) * N; 
// include every number the N times by ensuring rawRand is between 0 and randTruncation - 1 or regenerate.
unsigned long rawRand = rand();

while (rawRand >= randTruncation) {
    rawRand = rand();  
// with 64-bit int and range of 0-99 will need to generate two random numbers
// about 1 in every (2^63)/16 ~ 10^18 times (1 million million times)

// with 32-bit int and range of 0-99 will need to generate two random numbers 
// once every 46 million times.

}
cout << rawRand % N << stdl::endl;
于 2010-11-16T15:49:28.673 回答
4

请参阅man 3 rand- 您需要通过除以进行缩放RAND_MAX以获得范围 [0, 1] 之后,您可以将目标范围乘以 100。

于 2010-11-16T15:48:46.047 回答
-1

对于 min 到 max(包括)的范围,使用:int result = rand() % (max - min + 1) + min;

于 2010-11-16T15:49:53.290 回答
-4

您希望得到多长时间的答复。

最简单的方法是使用除以 101 的余数进行转换:

int value = rawRand % 101;

半纯粹主义者会使用双打重新调整:

double dbl = 100 * ((double)rawRand / RAND_MAX);
int ivalue = (int)(dbl + 0.5);   // round up for above 0.5

纯粹主义者会说 rand 不会产生随机数。

为了您的信息,随机数的质量是通过获取一个数字序列然后计算该序列的来源是随机的数学概率来衡量的。如果您追求随机性,那么使用余数的简单破解是一个非常糟糕的选择。

于 2010-11-16T15:59:59.887 回答
-5

rawRand % 101 将给出 [0-100](含)。

于 2010-11-16T15:48:57.620 回答
-5

有人发布了以下代码作为示例:

int rawRand = (rand() / RAND_MAX) * 100;

这是解决问题的无效方法,因为 rand() 和 RAND_MAX 都是整数。在 C++ 中,这会导致整数除法,这将截断结果小数点。由于 RAND_MAX >= rand(),该操作的结果是 1 或 0,这意味着 rawRand 只能是 0 或 100。正确的做法如下:

int rawRand = (rand() / static_cast<double>(RAND_MAX)) * 100;

由于一个操作数现在是双精度数,因此使用浮点除法,这将返回一个介于 0 和 1 之间的正确值。

于 2010-11-16T16:57:44.927 回答