如何缩小 rand() 中的数字?

发布于 2024-10-03 03:31:36 字数 307 浏览 9 评论 0原文

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

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 的范围内?

The following code outputs a random number each second:

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

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

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

        sleep(1);
    }
}

How might I size these numbers down so they're always in the range of 0-100?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

简单 2024-10-10 03:31:36

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

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

If you are using C++ and are concerned about good distribution you can use 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;
看透却不说透 2024-10-10 03:31:36

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

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

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

当然,该方法很慢,但它确实产生了良好的分布。一种稍微聪明的方法是找到小于 RAND_MAXN 的最大倍数,并将其用作上限。之后,就可以安全地获取结果 % (N + 1)

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

All the examples posted so far actually give badly distributed results. Execute the code often and create a statistic to see how the values become skewed.

A better way to generate a real uniform random number distribution in any range [0, N] is the following (assuming that rand actually follows a uniform distribution, which is far from obvious):

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

Of course, that method is slow but it does produce a good distribution. A slightly smarter way of doing this is to find the largest multiple of N that is smaller than RAND_MAX and using that as the upper bound. After that, one can safely take the result % (N + 1).

For an explanation why the naive modulus method is bad and why the above is better, refer to Julienne’s excellent article on using rand.

赠我空喜 2024-10-10 03:31:36

int rawRand = rand() % 101;

请参阅(了解更多详细信息):

rand - C++ 参考

其他人也指出,这不会为您提供尽可能最佳的随机数分布。如果这种事情在你的代码中很重要,你就必须这样做:

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

编辑

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

rand() 被认为有害 |走向本土 2013

int rawRand = rand() % 101;

See (for more details):

rand - C++ Reference

Others have also pointed out that this is not going to give you the best distribution of random numbers possible. If that kind of thing is important in your code, you would have to do:

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

EDIT

Three years on, I'm making an edit. As others mentioned, rand() has a great deal of issues. Obviously, I can't recommend its use when there are better alternatives going forward. You can read all about the details and recommendations here:

rand() Considered Harmful | GoingNative 2013

蝶舞 2024-10-10 03:31:36

你可以

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 位随机整数一样,每 10^18 次调用需要两次 rand() 调用。

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;

You can do

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

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

For the people downvoting; note one minute after this was originally posted I left the comment:

From http://www.cplusplus.com/reference/clibrary/cstdlib/rand "Notice though that this modulo operation does not generate a truly uniformly distributed random number in the span (since in most cases lower numbers are slightly more likely), but it is generally a good approximation for short spans."

With 64-bit ints and using 100 numbers as output, the numbers 0-16 are represented with 1.00000000000000000455 % of the numbers (an relative accuracy to identically distributed of 1% by about 10-18), while the numbers 17-99 are represented with 0.99999999999999999913 % of the numbers. Yes, not perfectly distributed, but a very good approximation for small spans.

Also note, where does the OP ask for identically distributed numbers? For all we know these are being used for purposes where a small deviations doesn't matter (e.g., anything other than cryptography -- and if they are using the numbers for cryptography this question is much too naive for them to be writing their own cryptography).

EDIT - For people who are truly concerned with having a uniform distribution of random numbers the following code works. Note this isn't necessarily optimal as with 64-bit random ints, it will require two calls of rand() once every 10^18 calls.

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;
橙味迷妹 2024-10-10 03:31:36

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

See man 3 rand -- you need to scale by dividing by RAND_MAX to obtain the range [0, 1] after which you can multiply by 100 for your target range.

落叶缤纷 2024-10-10 03:31:36

对于从最小值到最大值(含)的范围,请使用:int result = rand() % (max - min + 1) + min;

For the range min to max (inclusive), use: int result = rand() % (max - min + 1) + min;

流绪微梦 2024-10-10 03:31:36

您想要多长时间的答案。

最简单的方法是使用除以 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 不会产生随机数。

供您参考,随机数的质量是通过获取数字序列然后计算该序列的来源是随机的数学概率来测量的。如果您追求随机性,那么使用余数的简单黑客是一个非常糟糕的选择。

How long an answer would you like.

the simplest is to convert using the remainder when divided by 101:

int value = rawRand % 101;

A semipurist would rescale using doubles:

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

And a purist would say that rand does not produce random numbers.

For your info, the quality of random numbers is measured by taking a sequence of numbers and then calculating the mathematical probability that the source of that sequence was random. The simple hack using the remainder is a very poor choice if you are after randomness.

能怎样 2024-10-10 03:31:36

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

rawRand % 101 would give [0-100], inclusive.

汹涌人海 2024-10-10 03:31:36

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

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;

由于操作数为 1,所以现在是双精度浮点型使用点除法,它会返回 0 到 1 之间的正确值。

Some people have posted the following code as an example:

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

This is an invalid way of solving the problem, as both rand() and RAND_MAX are integers. In C++, this results in integral division, which will truncate the results decimal points. As RAND_MAX >= rand(), the result of that operation is either 1 or 0, meaning rawRand can be only 0 or 100. A correct way of doing this would be the following:

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

Since one the operands is now a double, floating point division is used, which would return a proper value between 0 and 1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文