RNG in classes

I am making a class to define a combination lock. The default constructor is supposed to set the 3 numbers in the combo to a random number between 1 and 39... now i have a pretty good understanding of how random number generation works i just don't know where to call the seed function...(unsigned (time(NULL))) would i put that in the .h file with the class the implementation file with the member function definitions or what? I'm not sure how to make the call with out it actually being in the int main(){...}
Putting the seed function in with the constructor will guarentee that it is called everytime a new instance of that object is created. This alleviates from you the burden of thought, which is always a good thing.
I wouldn't put the seed function in a class that uses random numbers. Instead it belongs in a class that generates random numbers.

The difference is, if you create multiple combination locks at the same time, seeding in their ctor will result in all of them having the same combination.
Interesting, I never realized that. It makes sence because if you're seeding with the time of day and generating the combos faster then the clock ticks over then you would end up with the same random numbers. Nice insight.
I see what both of you are saying. I don't intend on generating more than one lock at a time so i think computergeek01's solution is best for me now. However, could you explain how you would do it disch?
I don't intend on generating more than one lock at a time so i think computergeek01's solution is best for me now.


It still doesn't seem like it belongs there to me.

But whatever.

As for me... for serious projects I don't really use rand() (for this reason and others). Instead I made my own RNG class(es) based on other algorithms.

This is probably overkill for what you need... but here are snippits from a now mostly defunct lib I was working on way back when:

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
61
62
63
64
65
class RNGBase
{
public:
    //===============================================
    virtual         ~RNGBase()  {   }

    //===============================================
    //  Generating random numbers
    virtual u32     Get() = 0;              // to be supplied by the RNG
    inline u32      Get(u32 min,u32 max)    { return (max<=min) ? min : (Get() % (max-min) + min); }

    inline double   Real()
    { return ( double(Get()) / 4294967296.0 );             }

    inline double   Real1()
    { return ( double(Get()) / 4294967295.0 );             }

    //==================================================
    // overloaded parenthesis
    inline u32      operator () ()                  { return Get();             }
    inline u32      operator () (u32 min,u32 max)   { return Get(min,max);      }

    //================================================
    //  Reseeding
    inline void     TimeSeed()              { Reseed( static_cast<u32>(time(0)) );  }
    virtual void    Reseed(u32 seed) = 0;   // to be supplied by the RNG
};

//==================================================================

/*!
    %GMSimple32RNG is an implementation of a pRNG posted by George Marsaglia on Google
Groups.  It was casually posted without a name for the algorithm or any copyright information.
It is a very simplistic and lightweight algroithm.
*/

class GMSimple32RNG : public RNGBase
{
public:
    //=====================================================
    //  ctor
    GMSimple32RNG(bool seed = true)     {       if(seed) TimeSeed();    }

    //=====================================================
    //  the RNG
    virtual u32     Get()
    {
        return state = (69069*state) + 362437;
    }

    //=====================================================
    //  Seeding the RNG
    virtual void    Reseed(u32 seed)
    {
        state = seed;
    }

private:
    u32             state;
};

//================================================

extern GMSimple32RNG Rand;  // put a definition for this in a cpp file:
  // GMSimple32RNG Rand;  <- like this 


The idea was the RNGBase class abstracts it so that other algorithms are easy to drop in. This one is pretty basic, but I also had another one based on the ISAAC algorithm that's too large to post here.

The global Rand object allows for simple number generation. The overloaded parenthesis operator makes it very similar to cstdio's rand:

1
2
3
4
5
6
7
8
int somenumber = Rand.Get();  // verbose;
somenumber = Rand();  // same way

somenumber = Rand.Get(0,100);  // verbose ... number between [0..100)
somenumber = Rand(0,100);  // same, not verbose

double real = Rand.Real();  // between [0..1)
real = Rand.Real1();  // between [0..1] 


And since it's seeded in the ctor, you don't have to worry about calling srand or something similar.

The global object doesn't stop it from being objectified, so you can have multiple RNGs running in tandem if you need it:

1
2
3
4
GMSimple32RNG a;
GMSimple32RNG b;

// now we can get numbers from a or b without disturbing Rand's sequence 


EDIT: fixed a bit WTF bug in Get(min,max)
Last edited on
What the hell, here's the ISAAC one too:

isaac.h
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
61

#ifndef __DSHLIB_ISAAC__
#define __DSHLIB_ISAAC__

namespace dshlib
{

/*!

    %IsaacRNG is an implementation of the ISAAC algorithm for producing random numbers.
The ISAAC algorithm was designed by Robert Jenkis.  For additional information on
the algorithm, see the following links:
- http://www.burtleburtle.net/bob/rand/isaac.html
- http://www.burtleburtle.net/bob/rand/isaacafa.html

    Code in this implementation was translated from 'readable.c' which was declared
public domain and is available via the above links.

*/

class IsaacRNG : public RNGBase
{
public:
    //========================================
    //  ctor
    IsaacRNG(bool seed = true)     {       if(seed) TimeSeed();    }

    //========================================
    //  Generation
    virtual u32     Get();

    //========================================
    //  Reseeding
    virtual void    Reseed(u32 seed);
    void            ReseedFull(const u32 seeds[256]);


private:
    u32             mm[256];
    u32             aa;
    u32             bb;
    u32             cc;
    u8              step;

/*!
 \fn IsaacRNG(bool seed = true)
 \param[in] seed Set to \c false if RNG is to remain unseeded


 \fn void ReseedFull(const u32 seeds[256])
 \remarks This can be used to provide a larger seed to more completely seed the RNG.

*/

};

//================================================

}//namespace dshlib

#endif // __DSHLIB_ISAAC__ 


isaac.cpp:
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

#include "../common/common.h"
#include "rng.h"

//================================================
//  dshlib implementation of the ISAAC algorithm.
//    ISAAC algorithm by Robert Jenkins
//
//  see these pages for details:
//
//  http://www.burtleburtle.net/bob/rand/isaac.html
//  http://www.burtleburtle.net/bob/rand/isaacafa.html
//
//  Code was translated from 'readable.c' which was declared public domain,
//   and is available via the above links.

namespace dshlib
{
//=============================================================

void IsaacRNG::Reseed(u32 seed)
{
    // use the GMSimple32 RNG to fill the seeds for this RNG
    GMSimple32RNG r(false);
    r.Reseed(seed);
    u32 seeds[256];

    int i;
    for(i = 0; i < 256; ++i)
        seeds[i] = r();

    ReseedFull(seeds);
}

//=============================================================

static inline void mix(u32& a,u32& b,u32& c,u32& d,u32& e,u32& f,u32& g,u32& h)
{
    a^=b<<11;   d+=a;   b+=c;
    b^=c>>2;    e+=b;   c+=d;
    c^=d<<8;    f+=c;   d+=e;
    d^=e>>16;   g+=d;   e+=f;
    e^=f<<10;   h+=e;   f+=g;
    f^=g>>4;    a+=f;   g+=h;
    g^=h<<8;    b+=g;   h+=a;
    h^=a>>9;    c+=h;   a+=b;
}

void IsaacRNG::ReseedFull(const u32 seeds[256])
{
    aa = 0;
    bb = 0;
    cc = 0;
    step = 0;

    static const u32 GOLDENRATIO = 0x9E3779B9;

    u32 a, b, c, d, e, f, g, h;
    a=b=c=d=e=f=g=h=GOLDENRATIO;

    // scramble the golden ratio
    int i;
    for(i = 0; i < 4; ++i)
        mix(a,b,c,d,e,f,g,h);

    // shuffle up mm
    for(i = 0; i < 256; i += 8)
    {
        a += seeds[i  ];    b += seeds[i+1];    c += seeds[i+2];    d += seeds[i+3];
        e += seeds[i+4];    f += seeds[i+5];    g += seeds[i+6];    h += seeds[i+7];

        mix(a,b,c,d,e,f,g,h);

        mm[i  ] = a;    mm[i+1] = b;    mm[i+2] = c;    mm[i+3] = d;
        mm[i+4] = e;    mm[i+5] = f;    mm[i+6] = g;    mm[i+7] = h;
    }

    // do another pass to make sure the seed has full effect
    for(i = 0; i < 256; i += 8)
    {
        a += mm[i  ];   b += mm[i+1];   c += mm[i+2];   d += mm[i+3];
        e += mm[i+4];   f += mm[i+5];   g += mm[i+6];   h += mm[i+7];

        mix(a,b,c,d,e,f,g,h);

        mm[i  ] = a;    mm[i+1] = b;    mm[i+2] = c;    mm[i+3] = d;
        mm[i+4] = e;    mm[i+5] = f;    mm[i+6] = g;    mm[i+7] = h;
    }

    // count and discard the first 256 numbers
    //  not sure why, but the original algorithm did this.. so what the hell
    for(i = 0; i < 256; ++i)
        Get();
}

//=======================================================

u32 IsaacRNG::Get()
{
    if(!step)
    {
        cc += 1;
        bb += cc;
    }

    switch(step & 3)
    {
    case 0: aa ^= (aa<<13);  break;
    case 1: aa ^= (aa>> 6);  break;
    case 2: aa ^= (aa<< 2);  break;
    case 3: aa ^= (aa>>16);  break;
    }

    u32 x, y;

    x = mm[step];
    aa =            mm[ step   ^ 0x80] + aa;
    mm[step] = y =  mm[(x>>2)  & 0xFF] + aa + bb;
    bb =            mm[(y>>10) & 0xFF] + x;

    ++step;     // wraps at 8 bits
    return bb;
}

}//namespace dshlib 
What's this "u32" data type? Can I assume "unsigned 32-bit int"? That and "u8" are holding me back from following this code, although I about to read the links now so if it's explained in there then I'll see it.
u32 and u8 are typedefs.

unsigned 32-bit and unsigned 8-bit respectively.
Topic archived. No new replies allowed.