views:

506

answers:

6

Whenever I use the rand function in C++:

#include<iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;
int main(){
srand(time(0));
int n=(rand()%6)+1;
cout<<"The dice roll is "<<n<<"."<<endl;
}

I get a warning about conversion from time_t to int at line 5:

srand(time(0));

Is there any way to get rid of this warning?

+2  A: 

Use an explicit cast to get rid of the warning:

srand((int)time(0));
1800 INFORMATION
Yecch. This has a Y2038 problem if time_t is a double and int is 32 bits.
Dave
No Y2038 problem - you're not really interested in the exact date value, just some semi-random number to seed the random number generator with.
Mark Ransom
You're wrong; once the time_t value exceeds 2^31 - 1, the seed will be fixed there.
Dave
Actually, if the time_t value exceeds 2^31-1 you don't know what the seed will be - it's undefined behavior if the integral part of the float/double cannot be represented in the integer type.
Michael Burr
(Still a Y2038 problem.)
Dave
I really hope time_t doesn't end up as a double. 64bit int, sure, but I dread to think how much code is broken if casting time_t to an integer type yields undefined behaviour...
Steve Jessop
Don't be stupid, no one will be using this software in 2038 ;p
johnc
"(Still a Y2038 problem.)" - yup... So, how about (unsigned int) ((((uint64_t) time(0)) >> 32) ^ ((uint32_t) (uint64_t) (time(0))))? It ain't pretty, but you get a few more years before it goes undefined on you.
Michael Burr
As Yuval A points out, you're supposed to use an unsigned anyway, so that moves your problem (at least) another 68 years.
MSalters
"you get a few more years". Now that's some quality understatement.
Steve Jessop
+7  A: 

Actually, you should be using an an unsigned int with srand():

srand((unsigned) time(0));
Yuval A
Pedantic note - using static_cast formulation for the cast is more grep friendly.
Anonymous
+6  A: 

On A different note, this code:

rand()%6

is generally regarded as a bad practice. the lower bits of rand() are significantly less random than the higher bits. You'll get better randomness if you do:

(rand() >> 8)%6

for instance.

EDIT:

For more detail on this, see this note and also this article from Dr. Dobbs journal which at least hint at the reason:

Note: Do NOT use

  y = rand()  %  M;

as this focuses on the lower bits of rand(). For linear congruential random number generators, which rand() often is, the lower bytes are much less random than the higher bytes. In fact the lowest bit cycles between 0 and 1. Thus rand() may cycle between even and odd (try it out). Note rand() does not have to be a linear congruential random number generator. It's perfectly permissible for it to be something better which does not have this problem.

DDJ:

The most important point is that the lower bits of the output from the usual (linear congruential) random number generators are the least "random." That is, patterns in the lower bits are common. Hence, the output from the routine roll in your discussion is not surprising. Also, it is avoidable by relying on the upper bits to determine the integer returned.

For example, if you wanted to choose a random "true" or "false" value, and you used the code:

rand() % 2

Then you might end up seeing the pattern of results:

1,0,1,0,1,0,1,0,1,0 (etc)

This is obviously not that random, but it is a property of the linear congruential generator that might be in use. A better scheme altogether (for C++) might be to use the Boost.Random library which has support for all kinds of pluggable random generators (including Mersenne Twister which does not have this flaw).

shoosh
Could elaborate on that (I'm fairly new with C++)
Keand64
If you want elaboration on why some bits are more random than others, I have no idea. Sounds interesting! But the >> is a shift. Not to confused with its other use, which you've probably seen (cin>>some_string_var). Think of the number in binary being shifted to the right by 8 bits, with zeros coming in on the left. So 0110 1101 0001 0010 would become 0000 0000 0110 1101.
MatrixFrog
I edited the answer to provide some more detail.
1800 INFORMATION
+2  A: 

Two side notes:

  • The standard way of including C headers in C++ is like this: #include <cstdio>.
  • The parameter passed to time() is a pointer, and many people think that NULL is a more readable null pointer than 0.
Bastien Léonard
In C++, many people (Dr Stroustrup included) prefer to use 0 as a null pointer.
anon
+1  A: 

Also,

 rand() % 6

will introduce a small bias. Since RAND_MAX % 6 is 1, zero and one will turn up slightly more often than two through six. In this case, they be returned 5462 times for every 5461 times the higher numbers are returned, so you probably won't notice it. However, if the range of numbers you want is large, the bias can be significant. For example, if you did rand() % 32000, then number in the range 0 - 767 would turn up twice as often as those 768 - 32000.

James Curran
RAND_MAX % 6 is a number between 0 and 5, that's all you can say about it. There's a reason it's an implementation-provided macro.
MSalters
The specifics may vary between implementations, but the basic principle is the correct. (Also, RAND_MAX == 32767 is very close to ubiquitous on PC. And even if your library uses a different value, the chances that RAND_MAX % 6 == 5 -- needed for no bias -- is quite low)
James Curran
+2  A: 

To get rid of the warning you should use a static cast to an unsigned integer.

srand(static_cast<unsigned int>(time(0)));

On a related note, the results of rand should be shifted to the right to remove any bias in the lower bits.

int n = ((rand() >> 8) % 6) + 1;

Finally, in C++ the C time and standard libraries should be included as:

#include <ctime>
#include <cstdlib>

This will place the functions in the appropriate namespace, 'std'.

Tom