How does modulus and rand() work?

2019-01-04 14:18发布

So, I've been nuts on this.

rand() % 6 will always produce a result between 0-5.

However when I need between, let's say 6-12.

Should I have rand() % 6 + 6

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

So do I need to + 7 If I want the interval 6-12? But then, 0+7 =7. When will it randomize 6?

What am I missing here? Which one is the correct way to have a randomized number between 6 and 12? And why? It seems like I am missing something here.

标签: c++ random
4条回答
相关推荐>>
2楼-- · 2019-01-04 15:03

If C++11 is an option then you should use the random header and uniform_int_distrubution. As James pointed out in the comments using rand and % has a lot of issues including a biased distribution:

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

if you have to use rand then this should do:

rand() % 7 + 6

Update

A better method using rand would be as follows:

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

I obtained this from the C FAQ and it is explained How can I get random integers in a certain range? question.

Update 2

Boost is also an option:

#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 ;
}
查看更多
等我变得足够好
3楼-- · 2019-01-04 15:03

There are a couple of concepts here.

First, there's the range: [ denotes inclusive. ) denotes exclusive.

The modulus operator % n produces [0,n) - 0,..n-1

When you add a value to that result, you're adding the same value to both ends of the ranges:

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

Now, if n is 6, as it in in your case, your output will be [0,6)

%6 + 6 = [6,12)

Now what you want is [6,13)

Subtract 6 from that:

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

Second, there is the matter of using rand(). It depends on whether you really care if your data is random or not. If you do really care that it is random, I highly suggest watching Stefan T Lavalej's talk on the pitfalls of using rand() at Going Native 2013 this year. He also goes into what you should use.

If the randomness of rand() doesn't matter to you, then by all means use it.

查看更多
Viruses.
4楼-- · 2019-01-04 15:08

The modulus operation a % b computes the remainder of the division a / b. Obviously the remainder of a division must be less than b and if a is a random positive integer then a%b is a random integer in the range 0 .. (b-1)


In the comments you mention:

rand()%(max-min)+min

This algorithm produces values in the half-open range [min, max). (That is, max is outside the range, and simply denotes the boundary. Since we're talking about ranges of integers this range is equivalent to the closed range [min, max-1].)

When you write '0 - 5' or '6 - 12' those are closed ranges. To use the above equation you have to use the values that denote the equivalent half open range: [0, 6) or [6, 13).

rand() % (6-0) + 0

rand() % (13-6) + 6

Note that rand() % (max-min) + min is just a generalization of the rule you've apparently already learned: that rand() % n produces values in the range 0 - (n-1). The equivalent half-open range is [0, n), and rand() % n == rand() % (n-0) + 0.

So the lesson is: don't confuse half-open ranges for closed ranges.


A second lesson is that this shows another way in which <random> is easier to use than rand() and manually computing your own distributions. The built-in uniform_int_distribution allows you to directly state the desired, inclusive range. If you want the range 0 - 5 you say uniform_int_distibution<>(0, 5), and if you want the range 6 - 12 then you say 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 is more terse, but that doesn't mean it is easier to use.

查看更多
时光不老,我们不散
5楼-- · 2019-01-04 15:13

You need rand() % 7 + 6.

Lowest number from rand() %7: 0. Highest number from rand() %7: 6.

0 + 6 = 6. 6 + 6 = 12.

查看更多
登录 后发表回答