模数和rand()如何工作?

时间:2013-10-23 22:11:19

标签: c++ random

所以,我一直很坚定。

rand()%6将始终产生0-5之间的结果。

然而,当我需要之间时,让我们说6-12。

我应该有rand()%6 + 6

0+6 = 6.
1+6 = 7.
...
5+6 = 11. ???

所以我需要+ 7如果我想要6-12的间隔?但是,0 + 7 = 7。什么时候会随机化6?

我在这里缺少什么?哪一个是6到12之间随机数的正确方法?为什么?好像我在这里遗漏了一些东西。

4 个答案:

答案 0 :(得分:10)

如果 C ++ 11 是一个选项,那么您应该使用random headeruniform_int_distrubution。正如詹姆斯在评论中指出的那样使用 rand %有很多问题,包括有偏见的分布:

#include <iostream>
#include <random>

int main()
{
    std::random_device rd;

    std::mt19937 e2(rd());

    std::uniform_int_distribution<int> dist(6, 12);

    for (int n = 0; n < 10; ++n) {
            std::cout << dist(e2) << ", " ;
    }
    std::cout << std::endl ;
}

如果你必须使用rand,那么应该这样做:

rand() % 7 + 6

更新

使用rand的更好方法如下:

6 + rand() / (RAND_MAX / (12 - 6 + 1) + 1)

我是从 C FAQ 获得的,并解释了How can I get random integers in a certain range?问题。

更新2

Boost也是一个选项:

#include <iostream>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>

int main()
{
  boost::random::mt19937 gen;
  boost::random::uniform_int_distribution<> dist(6, 12);

  for (int n = 0; n < 10; ++n) {
    std::cout << dist(gen) << ", ";
  }
  std::cout << std::endl ;
}

答案 1 :(得分:4)

你需要rand()%7 + 6。

rand()%7:0中的最小数字。 来自rand()%7:6的最高数字。

0 + 6 = 6。 6 + 6 = 12。

答案 2 :(得分:4)

模数运算a % b计算除法a / b的余数。显然,除法的余数必须小于b,如果a是随机正整数,则a%b是0 ...(b-1)范围内的随机整数


在你提到的评论中:

  

兰特()%(最大 - 最小)+分钟

该算法产生半开范围[min,max]的值。 (也就是说,max超出范围,只是表示边界。由于我们讨论的是整数范围,因此这个范围相当于闭合范围[min,max-1]。)

当你写'0 - 5'或'6 - 12'时,这些是封闭的范围。要使用上面的等式,您必须使用表示等效半开范围的值:[0,6]或[6,13)。

rand() % (6-0) + 0

rand() % (13-6) + 6

请注意,rand() % (max-min) + min只是您已经学过的规则的概括:rand() % n生成0 - (n-1)范围内的值。等效的半开范围是[0,n),rand() % n == rand() % (n-0) + 0

所以教训是:不要混淆封闭范围的半开范围。


第二个教训是,这显示了<random>rand()更容易使用并手动计算您自己的发行版的另一种方式。内置uniform_int_distribution允许您直接说明所需的包含范围。如果你想要范围0 - 5你说uniform_int_distibution<>(0, 5),如果你想要范围6 - 12,那么你说uniform_int_distribution<>(6, 12)

#include <random>
#include <iostream>

int main() {
  std::default_random_engine eng;
  std::uniform_int_distribution<> dist(6, 12);

  for (int i=0; i<10; ++i)
    std::cout << dist(eng) << " ";
}

rand()%7+6更简洁,但这并不意味着它更容易使用。

答案 3 :(得分:1)

这里有几个概念。

首先,范围是:[表示包容性。 )表示排他性。

模数运算符%n产生[0,n) - 0,.. n-1

为该结果添加值时,您将向范围的两端添加相同的值:

%n + 6 = [n,n+6)

现在,如果n为6,就像你的情况一样,你的输出将是[0,6)

%6 + 6 = [6,12)

现在你想要的是[6,13)

从中减去6:

[0,7) + 6 => n%7 + 6

其次,有使用rand()的问题。这取决于您是否真的关心您的数据是否随机。如果你确实关心它是随机的,我强烈建议今年在Going Native 2013上观看Stefan T Lavalej关于the pitfalls of using rand()的演讲。他也会介绍你应该使用的东西。

如果rand()的随机性对你无关紧要,那么一定要使用它。