5

How I can get in C++ random value from 1 to 12?

So I will have 3, or 6, or 11?

5
  • 17
    Did anyone else think int Random(){ return 4; /*Guaranteed random -- Determined by dice roll */ } Commented Feb 12, 2010 at 19:25
  • I do think that the explanatory note is both superfluous and add ambiguity; there are other values between 1 and 12 (an infinite number in fact) Commented Feb 12, 2010 at 19:35
  • I need this one zero before 3, or 4 to automatic filling in some application, so I need type in day: 01 not 1, and in months - 08 not 8 Commented Feb 12, 2010 at 19:35
  • Ah, so your just needing to convert these numbers generated into a 2 digit fixed width number(as a string)? Commented Feb 12, 2010 at 19:41
  • 7
    Yikes. The formatting of the values has nothing to do with the values. You can format them any way you want after you have generated them. Commented Feb 12, 2010 at 19:42

5 Answers 5

16

Use the following formula:

M + rand() / (RAND_MAX / (N - M + 1) + 1), M = 1, N = 12 

and read up on this FAQ.

Edit: Most answers on this question do not take into account the fact that poor PRN generators (typically offered with the library function rand()) are not very random in the low order bits. Hence:

rand() % 12 + 1 

is not good enough.

Sign up to request clarification or add additional context in comments.

5 Comments

Using division gives only a minute improvement by itself -- the results may be more random, but they're still usually skewed. Assuming rand() produces all numbers up to RAND_MAX with equal probability, this will NOT produce numbers from 1 to 12 with equal probability, except in the (vanishingly rare) case that RAND_MAX happens to be a multiple of 12.
+1 for raising the statistical bias issue from using the naive % approach.
@Jerry: to be fair the FAQ linked gives other solutions.
@Clifford: I hadn't checked the link, but you're right. Then again, if memory serves, I was partially responsible for what's in the FAQ...
Actually, re-checking, it looks like I probably wasn't. For anybody who cares what I'm talking about, see: groups.google.com/group/comp.lang.c/browse_frm/thread/…
9
#include <iomanip> #include <iostream> #include <stdlib.h> #include <time.h> // initialize random seed srand( time(NULL) ); // generate random number int randomNumber = rand() % 12 + 1; // output, as you seem to wan a '0' cout << setfill ('0') << setw (2) << randomNumber; 

to adress dirkgently's issue maybe something like that would be better?

// generate random number int randomNumber = rand()>>4; // get rid of the first 4 bits // get the value randomNumer = randomNumer % 12 + 1; 

edit after mre and dirkgently's comments

5 Comments

Poor method because the low-order bits of many random number generators are distressingly non-random. Read the FAQ I posted in my answer.
@dirkgently I bet this is just homework, so he doesn't much care if the numbers aren't truly random.
+1 You were just too fast ;) Maybe change to std::cout
@Earlz: Homework is about learning things right. Not copy-pasting. Hence, my answer does not have a full solution. A hint only. A very, very important hint to keep in mind.
<Pedantic> Missing #include <iomanip> and it's std::setfill and std::setw </Pedantic>
4

Is there some significance to the leading zero in this case? Do you intend for it to be octal, so the 12 is really 10 (in base 10)?

Getting a random number within a specified range is fairly straightforward:

int rand_lim(int limit) { /* return a random number between 0 and limit inclusive. */ int divisor = RAND_MAX/(limit+1); int retval; do { retval = rand() / divisor; } while (retval > limit); return retval; } 

(The while loop is to prevent skewed results -- some outputs happening more often than others). Skewed results are almost inevitable when/if you use division (or its remainder) directly.

If you want to print it out so even one-digit numbers show two digits (i.e. a leading 0), you can do something like:

std::cout << std::setw(2) << std::setprecision(2) << std::setfill('0') << number; 

Edit: As to why this works, and why a while loop (or something similar) is needed, consider a really limited version of a generator that only produces numbers from, say, 0 to 9. Assume further that we want numbers in the range 0 to 2. We can basically arrange the numbers in a table:

0 1 2 3 4 5 6 7 8 9 

Depending on our preference we could arrange the numbers in columns instead:

0 3 6 1 4 7 2 5 8 9 

Either way, however, we end up with the one of the columns having one more number than any of the others. 10 divided by 3 will always have a remainder of 1, so no matter how we divide the numbers up, we're always going to have a remainder that makes one of the outputs more common than the others.

The basic idea of the code above is pretty simple: after getting a number and figuring where in a "table" like one above that number would land, it checks whether the number we've got is the "odd" one. If it is, another iteration of the loop is executed to obtain another number.

There are other ways this could be done. For example, you could start by computing the largest multiple of the range size that's still within the range of the random number generator, and repeatedly generate numbers until you get one smaller than that, then divide the number you receive to get it to the right range. In theory this could even be marginally more efficient (it avoids dividing the random number to get it into the right range until it gets a random number that it's going to use). In reality, the vast majority of the time, the loop will only execute one iteration anyway, so it makes very little difference what we execute inside or outside the loop.

1 Comment

This seems correct to me, but it is not immediately obvious that it is. Could you elaborate on why it is correct, please?
1

You can do this, for example:

#include <cstdlib> #include <cstdio> #include <time.h> int main(int argc, char **argv) { srand(time(0)); printf("Random number between 1 and 12: %d", (rand() % 12) + 1); } 

The srand function will seed the random number generator with the current time (in seconds) - that's the way it's usually done, but there are also more secure solutions.

rand() % 12 will give you a number between 0 and 11 (% is the modulus operator), so we add 1 here to get to your desired range of 1 to 12.

In order to print 01 02 03 and so on instead of 1 2 3, you can format the output:

printf("Random number between 01 and 12: %02d", (rand() % 12) + 1); 

Comments

-2

(rand() % 12 + 1).ToString("D2")

3 Comments

The question is tagged C++, not C# or whatever that code is.
if someone can't figure out how to convert that to c++ then I question the ability to do any programming.
@tim:but at that point, it's basically not doing much more than echoing back the question. How do a print with two decimal places? Do the conversion with two decimal places! Oh, and along with that giving the same (bad) advice about how to reduce the range as at least half a dozen others...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.