如何缩小 rand() 中的数字?
以下代码每秒输出一个随机数:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
如果您使用 C++ 并且关心良好的分布,您可以使用
TR1C++11
。If you are using C++ and are concerned about good distribution you can use
TR1C++11<random>
.到目前为止发布的所有示例实际上都给出了分布很差的结果。经常执行代码并创建统计数据以查看值如何倾斜。
生成任意范围 [0, N] 内的真实均匀随机数分布的更好方法如下(假设
rand
实际上遵循均匀分布,这远非显而易见):当然,该方法很慢,但它确实产生了良好的分布。一种稍微聪明的方法是找到小于
RAND_MAX
的 N 的最大倍数,并将其用作上限。之后,就可以安全地获取结果 % (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):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 theresult % (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
.请参阅(了解更多详细信息):
rand - C++ 参考
其他人也指出,这不会为您提供尽可能最佳的随机数分布。如果这种事情在你的代码中很重要,你就必须这样做:
编辑
三年过去了,我正在进行编辑。正如其他人提到的,rand() 存在很多问题。显然,当未来有更好的替代方案时,我不建议使用它。您可以在此处阅读有关详细信息和建议的所有信息:
rand() 被认为有害 |走向本土 2013
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:
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
你可以
为那些投反对票的人做;请注意,在本文最初发布一分钟后,我留下了评论:
对于 64 位整数并使用 100 个数字作为输出,数字 0-16 用 1.00000000000000000455 % 的数字表示(1% 同分布的相对精度约为 10-18),而数字 17-99 用数字的 0.99999999999999999913 % 表示。是的,不是完美分布,但对于小跨度来说是一个非常好的近似值。
另请注意,OP 在哪里要求相同分布的数字?据我们所知,这些数据被用于小偏差无关紧要的目的(例如,除了密码学之外的任何东西——如果他们使用数字进行密码学,那么这个问题对于他们来说太天真了,无法编写自己的密码学) )。
编辑 - 对于真正关心随机数均匀分布的人,以下代码有效。请注意,这不一定是最佳的,就像 64 位随机整数一样,每 10^18 次调用需要两次
rand()
调用。You can do
For the people downvoting; note one minute after this was originally posted I left the comment:
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.请参阅
man 3 rand
- 您需要通过除以RAND_MAX
来进行缩放以获得范围 [0, 1],然后乘以 100 即可得到目标范围。See
man 3 rand
-- you need to scale by dividing byRAND_MAX
to obtain the range [0, 1] after which you can multiply by 100 for your target range.对于从最小值到最大值(含)的范围,请使用:int result = rand() % (max - min + 1) + min;
For the range min to max (inclusive), use:
int result = rand() % (max - min + 1) + min;
您想要多长时间的答案。
最简单的方法是使用除以 101 时的余数进行转换:
半纯粹主义者会使用双精度数重新缩放:
纯粹主义者会说 rand 不会产生随机数。
供您参考,随机数的质量是通过获取数字序列然后计算该序列的来源是随机的数学概率来测量的。如果您追求随机性,那么使用余数的简单黑客是一个非常糟糕的选择。
How long an answer would you like.
the simplest is to convert using the remainder when divided by 101:
A semipurist would rescale using doubles:
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.
rawRand % 101 将给出 [0-100](含)。
rawRand % 101 would give [0-100], inclusive.
有些人发布了以下代码作为示例:
这是解决问题的无效方法,因为 rand() 和 RAND_MAX 都是整数。在 C++ 中,这会导致积分除法,从而截断结果小数点。当 RAND_MAX >= rand() 时,该操作的结果为 1 或 0,这意味着 rawRand 只能为 0 或 100。执行此操作的正确方法如下:
由于操作数为 1,所以现在是双精度浮点型使用点除法,它会返回 0 到 1 之间的正确值。
Some people have posted the following code as an example:
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:
Since one the operands is now a double, floating point division is used, which would return a proper value between 0 and 1.