Different method, converting time for rand

I was wondering if there was a method to make the time seed for rand increment it's randomness in milliseconds or thousandths of a millisecond as a method to make it actually random. If I run this code as it is I get numbers like 8834,8842,8856 .etc. so unless I'm going to run it then wait an hour or 2 then run it again this code is kinda useless as far as RNG goes. Though I suppose it may work for the dice roller program I learned it from(although still being predictable output) but for any bigger numbers I don't see it being of much use.

 
  srand(static_cast<unsigned int>(time(0)));
Sounds like you misunderstand how PRNGs work.

rand() is basically a mathematical computation. It runs an input number 'x' through some computations, and results in output 'y'.

The output 'y' becomes the input 'x' for the next call to rand(). So each time you call rand, it is using it's previous output as its new input. Thus it generates a new number each time.

All srand() does is give the computations that first 'x' input -- it gives it a seed... a starting point... from which the computations can start.


Using time() as the seed is effective because it's virtually guaranteed to be unique each time the program starts.. ensuring that the computation will start with different input... generating a different stream of output numbers each time.


second... millisecond... microsecond granularity doesn't really matter. The point is to have a unique seed. The 1 second granularity offered by time() works just fine unless you run the program multiple times within the same 1 second window (in which case each instance of the program will produce the same stream of random numbers).



If you are getting predictable output instead of random output... it's much more likely that you are misusing rand. Can you post some example code that illustrates the problem you're seeing?
Last edited on
in your code, do you call srand() more than once? It should be called just once at the start of execution (usually at the beginning of main).

Also, if you are re-running the program again after only a brief time has elapsed there may be some visible pattern in the initial random number generated. It can help to begin by seeding the generator with srand, then call rand() to generate one or more numbers which are simply discarded, before going on to execute the rest of the program.
> begin by seeding the generator with srand, then call rand() to generate one or more numbers
> which are simply discarded, before going on to execute the rest of the program.

+1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <cstdlib>
#include <ctime>

void srand_and_warmup( int seed = std::time( nullptr ), int discard = 16 )
{
    std::srand( seed ) ;
    for( int i = 0 ; i < discard ; ++i ) std::rand() ;
}

int main()
{
    srand_and_warmup() ;
    std::cout << std::rand() << '\n' ;
}

http://coliru.stacked-crooked.com/a/db40c49328e3644f
Last edited on
-1

I've seen the "warmup" thing suggested a few times... but I've never once seen it make a bit of difference.

JLBorges' same code with discard=0 produces just as random of numbers:

http://coliru.stacked-crooked.com/a/553df4e95f2eda9e
Last edited on
Whether or not warmup is required may depend on the context.
Related thread:
http://www.cplusplus.com/forum/beginner/135383/
> but I've never once seen it make a bit of difference.

Then you deserve to be given the opportunity to see it for the first time:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <Windows.h>

void srand_with_warmup( int seed = std::time( nullptr ), int discard = 16 )
{
    std::srand( seed ) ;
    for( int i = 0 ; i < discard ; ++i ) std::rand() ;
}

void srand_disch( int seed = std::time( nullptr ) )
{
    std::srand( seed ) ;
}

int main( )
{
    const int N = 4 ;
    
    std::cout << "warmup: " ;
    for( int i = 0 ; i < N ; ++i )
    {
        srand_with_warmup() ;
        std::cout << std::rand() << ' ' ;
        Sleep( 1000 ) ;
    }

    std::cout << "\ndisch: " ;
    for( int i = 0 ; i < N ; ++i )
    {
        srand_disch() ;
        std::cout << std::rand( ) << ' ' ;
        Sleep( 1000 ) ;
    }
}

warmup: 343 27161 21211 15261 
disch: 8771 8774 8778 8781 

http://rextester.com/KQHU41415
Yeah I guess it depends on the rand() implementation and the RNG used. I'm surprised that an implementation would be so shoddy, though.

I mean... come on....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// custom rand()/srand() functions that probably are better than
//  some distributions of rand()

namespace
{
    unsigned state = 0;
}

void srand(unsigned seed)
{
    state = seed;
}

unsigned rand()
{
    return state = (69069*state) + 362437;
}
Last edited on
1
2
> // custom rand()/srand() functions that probably are better than
> //  some distributions of rand() 


This particular one appears to be truly dreadful:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <Windows.h>
#include <algorithm>
#include <numeric>
#include <iterator>

namespace disch
{
    namespace
    {
        unsigned state = 0;
    }

    void srand( unsigned seed )
    {
        state = seed;
    }

    unsigned rand( )
    {
        return state = ( 69069 * state ) + 362437;
    }
}

const int N = 6 ;
void analyse( const char* tag, const unsigned int(&seq)[N] )
{
    std::cout << tag << ": " ;
    for( auto v : seq ) std::cout << v << ' ' ;
    std::cout << "\nsorted? " << std::boolalpha << std::is_sorted( seq, seq + N ) << '\n' ;
    std::cout << "adjacent difference: " ;
    unsigned int diff[ N ] ;
    std::adjacent_difference( seq, seq + N, diff ) ;
    std::copy( diff+1, diff+N, std::ostream_iterator<unsigned int>( std::cout, " " ) ) ;
    std::cout << "\n\n" ;
}

int main( )
{
    unsigned int rand[N], high[ N ], low[ N ] ;

    for( int i = 0 ; i < N ; ++i )
    {
        disch::srand( std::time( nullptr ) ) ;
        const auto r = disch::rand( ) ;
        rand[ i ] = r ;
        high[ i ] = r >> 16 ;
        low[ i ] = r & 0xffff ;
        Sleep( 1000 ) ;
    }

    analyse( "disch rand", rand ) ;
    analyse( "high order bits of disch rand", high ) ;
    analyse( "low order bits of disch rand", low ) ;
}

disch rand: 3995995592 3996064661 3996202799 3996271868 3996340937 3996410006 
sorted? true
adjacent difference: 69069 138138 69069 69069 69069 

high order bits of disch rand: 60974 60975 60977 60978 60979 60980 
sorted? true
adjacent difference: 1 2 1 1 1 

low order bits of disch rand: 3528 7061 14127 17660 21193 24726 
sorted? true
adjacent difference: 3533 7066 3533 3533 3533

http://rextester.com/YSW68463

Even with warmup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <Windows.h>
#include <algorithm>
#include <numeric>
#include <iterator>

namespace disch
{
    namespace
    {
        unsigned state = 0;
    }

    void srand( unsigned seed )
    {
        state = seed;
    }

    unsigned rand( )
    {
        return state = ( 69069 * state ) + 362437;
    }
}

const int N = 6 ;
void analyse( const char* tag, const unsigned int(&seq)[N] )
{
    std::cout << tag << ": " ;
    for( auto v : seq ) std::cout << v << ' ' ;
    std::cout << "\nsorted? " << std::boolalpha << std::is_sorted( seq, seq + N ) << '\n' ;
    std::cout << "adjacent difference: " ;
    unsigned int diff[ N ] ;
    std::adjacent_difference( seq, seq + N, diff ) ;
    std::copy( diff+1, diff+N, std::ostream_iterator<unsigned int>( std::cout, " " ) ) ;
    std::cout << "\n\n" ;
}

int main()
{
    unsigned int rand[N], high[ N ], low[ N ] ;
    const int discard = 16 ;

    for( int i = 0 ; i < N ; ++i )
    {
        disch::srand( std::time( nullptr ) ) ;
        for( int j = 0 ; j < discard ; ++j ) disch::rand() ;

        const auto r = disch::rand( ) ;
        rand[ i ] = r ;
        high[ i ] = r >> 16 ;
        low[ i ] = r & 0xffff ;
        Sleep( 1000 ) ;
    }

    analyse( "disch rand with warmup", rand ) ;
    analyse( "high order bits of disch rand with warup", high ) ;
    analyse( "low order bits of disch rand with warmup", low ) ;
}

disch rand with warmup: 41191852 4044241593 3752324038 3460406483 3168488928 2876571373 
sorted? false
adjacent difference: 4003049741 4003049741 4003049741 4003049741 4003049741 

high order bits of disch rand with warup: 628 61710 57255 52801 48347 43892 
sorted? false
adjacent difference: 61082 4294962841 4294962842 4294962842 4294962841 

low order bits of disch rand with warmup: 35244 15033 60358 40147 19936 65261 
sorted? false
adjacent difference: 4294947085 45325 4294947085 4294947085 45325

http://rextester.com/CTG72276
Fair enough. I withdraw my -1 comment.

=P
Topic archived. No new replies allowed.