9

I have two questions.

  1. What other ways are there to seed a psuedo-random number generator in C++ without using srand(time(NULL))?

  2. The reason I asked the first question. I'm currently using time as my seed for my generator, but the number that the generator returns is always the same. I'm pretty sure the reason is because the variable that stores time is being truncated to some degree. (I have a warning message saying, "Implicit conversion loses integer precision: 'time_t' (aka 'long') to 'unsigned int') I'm guessing that this is telling me that in essence my seed will not change until next year occurs. For my purposes, using time as my seed would work just fine, but I don't know how to get rid of this warning.

I have never gotten that error message before, so I assume it has something to do with my Mac. It's 64-bit OS X v10.8. I'm also using Xcode to write and compile, but I had no problems on other computers with Xcode.

Edit: After toying and researching this more, I discovered a bug that 64-bit Macs have. (Please correct me if I am mistaken.) If you try to have your mac select a random number between 1 and 7 using time(NULL) as the seed, you will always get the number four. Always. I ended up using mach_absolute_time() to seed my randomizer. Obviously this eliminates all portability from my program... but I'm just a hobbyist.

Edit2: Source code:

#include <iostream>
#include <time.h>

using namespace std;

int main(int argc, const char * argv[]) {

srand(time(NULL));

cout << rand() % 7 + 1;

return 0;
}

I ran this code again to test it. Now it's only returning 3. This must be something to do with my computer and not the C++ itself.

  • 2
    See also: [Is there an alternative to using time to seed a random number generation?](http://stackoverflow.com/questions/7617587/is-there-an-alternative-to-using-time-to-seed-a-random-number-generation) – Mysticial Aug 13 '12 at 23:08
  • Just like gardening, you only need to plant a seed once. – Greg Hewgill Aug 13 '12 at 23:08
  • I once had similiar behaviour and I found that the intial numbers were the same, but if I printed a bunch of random numbers in a row they were different. Usually the first one was the same in each run, but by the second or third time through the print loop it was different. Try printing a few in a row and verify that run-to-run they are always the same... – fooOnYou Aug 13 '12 at 23:56
  • Do you use correspondent to srand() generator? rand()? – klm123 Aug 14 '12 at 01:47
  • @Redmastif: You are mistaken. rand() works perfectly for me. – Martin York Aug 14 '12 at 03:23
  • @LokiAstari: must be my computer then. –  Aug 14 '12 at 20:35
  • @Redmastif: Unlikely. Show us the code we can then comment more accurately. As long as you call srand() **only once** in the application then calls to rand() will follow a predetermined random sequence (to the human eye). – Martin York Aug 14 '12 at 20:51

4 Answers4

13

Tl;dr but, most likely, you're doing it wrong. You're only supposed to set the seed once, whereas you might have something like:

for ( ... )
{
   srand(time(NULL));
   whatever = rand();
}

when it should be

srand(time(NULL));
for ( ... )
{
   whatever = rand();
}
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 3
    If you can't easily avoid seeding it more than once for some reason, you can use: `srand(rand() ^ time(NULL));`. That will do no harm if repeated. – David Schwartz Aug 13 '12 at 23:10
  • @DavidSchwartz, what might be such a reason? – eq- Aug 13 '12 at 23:12
  • @eq-: If you have a function that needs to generate a random number and you have no easy way to tell in the function whether or not the random number generator has already been seeded. For example, all the code that calls you may be code that you don't maintain. – David Schwartz Aug 13 '12 at 23:13
  • @DavidSchwartz, personally I see no harm in a library producing predictable "random" results due to improper seeding but yes, that is of course true. – eq- Aug 13 '12 at 23:16
  • @eq-: It depends on the purpose of the library. If the purpose is fundamentally to provide those results, then sure. But if the caller would really have no reason to think the library needs the RNG seeded, that could be a serious problem. This is especially true if you're modifying an existing library that currently works fine even if the RNG isn't seeded. (Although I think there's a fair point that if it's not important that the results be random, why bother? And if it is important, you shouldn't be using `rand` but something better.) – David Schwartz Aug 13 '12 at 23:22
  • @Luchian Grigore: I only have a call to it once in the beginning of my `main()` function. Then in a `while()` loop I have I make repeated calls for a random number. The problem is that no matter how many times I run the program, the "random" number is always the same. –  Aug 14 '12 at 01:14
  • The danger of seeding in a loop like that with the time is you may end up seeding with the same number multiple times if the loop is faster than time(NULL) – kbickar Sep 27 '15 at 23:58
7

1.Not really. You can ask user to input random seed, for example. Or use some other system parameters, but this won't make a difference.

2.To rid of this warning you have to do explicit conversion. Like:

unsigned int time_ui = unsigned int( time(NULL) );
srand( time_ui );

or

unsigned int time_ui = static_cast<unsigned int>( time(NULL) );

or

unsigned int time_ui = static_cast<unsigned int>( time(NULL)%1000 );

to check whether this is really conversion problem you can simply output your time on the screen and see yourself

std::cout << time(NULL);
klm123
  • 12,105
  • 14
  • 57
  • 95
  • I printed `time(NULL)` on my screen and it was working fine. It changed every second. However, none of your implementations worked for me, no matter how I tweaked them. Accept because you at least got me started. Thanks. –  Aug 14 '12 at 01:39
  • have you tried to check time_ui value, right before you give it to srand() function? – klm123 Aug 14 '12 at 01:43
  • Yes. The way this is behaving, it's almost as if the seed is by the number if digits in the seed, not the number itself. I say this because when I use the modulus operation, the random number changes. –  Aug 14 '12 at 01:51
  • will the example from http://www.cplusplus.com/reference/clibrary/cstdlib/srand/ work for you? – klm123 Aug 14 '12 at 01:56
  • No, sorry. I just went and made a small separate program just to spit out random numbers. With the `time(NULL)` seed the program worked fine. So there is something else wrong with my original source code and the way that I'm catching the random number. Sorry to bother everyone with a pointless question. Haha. –  Aug 14 '12 at 02:00
5

You should see random once at the begining of you program:

int main()
{
    // When testing you probably want your code to be deterministic
    // Thus don't see random and you will get the same set of results each time
    // This will allow you to use unit tests on code that use rand().
    #if !defined(TESTING)
    srand(time(NULL));  // Never call again
    #endif

    // Your code here.

}
Martin York
  • 257,169
  • 86
  • 333
  • 562
0

For x86, direct call to the CPU time stamp counter rdtsc, instead of a library function TIME(NULL), could be used. Below 1) reads timestamp 2) seed RAND in assembly:

rdtsc
mov edi, eax
call    srand

For C++, the following would do the job with g++ compiler.

asm("rdtsc\n"
    "mov edi, eax\n"
    "call   srand");

NOTE: But may not be recommended if code is running in virtual machine.

codechimp
  • 1,509
  • 1
  • 14
  • 21
  • 3
    That inline asm isn't safe; it doesn't tell the compiler that you're clobbering registers, and the red-zone below `rsp` by making a function call. If it happens to work in your program, that's 1) luck and 2) probably because you compiled with optimizations disabled, so the compiler wasn't keeping anything in registers anyway. **DO NOT USE INLINE ASM FOR THIS. Use [`__int64 _rdtsc (void)` from `immintrin.h`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=1827,4456,4570,4570,2667,2667,719,4251&techs=SSE,SSE2,SSE3,SSSE3,SSE4_1,SSE4_2,AVX,AVX2,AVX_512,Other&text=rdts)** – Peter Cordes Dec 01 '17 at 05:52
  • Even the intrinsic RTDSC is probably still inappropriate for seeding. The time function returns the time in seconds since midnight, January 1, 1970, whereas RTDSC returns the elapsed time since the computer booted. Suppose you always run your program on boot. It is possible (unlikely, but possible) that you could call RTDSC at the exact same elapsed time on two different boots, in which case the two runs would produce the same random sequence. This would never happen with time(). – victimofleisure Apr 16 '23 at 18:50