nidan
asked on
Help with random seed
I have a template class called RandomAtom which generates either a random lowercase letter or a random digit. In my main program I have defined a function called RandomItem. It is overloaded to produce either a random string of some parameterized length, or a random number of some paramaterized length. It uses my RandomAtom function. The problem is this: I don't know where to set the seed of the RandomAtom class so I can generate lets say 10 distinct strings or numbers. Someone told me to set the random seed in main, then make the RandomAtom object a parameter of my RandomItem function. I tried this and it generated the same string/number. Here is my code:
int randomItem(int len, RandomAtom<int> atom)
{
int thisDigit = 0;
int retVal = 0;
while (thisDigit == 0) thisDigit = atom.randomIntChar(); // first digit cannot be zero
while (len--)
{
retVal *= 10;
retVal += thisDigit;
thisDigit = atom.randomIntChar();
}
return retVal;
}
char* randomItem(int len, RandomAtom<char> atom)
{
char *retVal = new char[len + 1]; // new string
retVal[len] = '\0';
while (len--) {
retVal[len] = atom.randomIntChar(); // fill it backwards
}
return retVal;
}
int main()
{
RandomAtom<int> atom(GetTickCount());
for(int i = 0; i < 10; i++)
{
cout << randomItem(3, atom) << endl;
}
return 0;
}
This code generates the same 3 digit number 10 times.
Example usage of the class RandomAtom:
RandomAtom<int> atom(seed);
atom.randomIntChar(); // generate a random digit
Can someone help me find my error? Thanks.
int randomItem(int len, RandomAtom<int> atom)
{
int thisDigit = 0;
int retVal = 0;
while (thisDigit == 0) thisDigit = atom.randomIntChar(); // first digit cannot be zero
while (len--)
{
retVal *= 10;
retVal += thisDigit;
thisDigit = atom.randomIntChar();
}
return retVal;
}
char* randomItem(int len, RandomAtom<char> atom)
{
char *retVal = new char[len + 1]; // new string
retVal[len] = '\0';
while (len--) {
retVal[len] = atom.randomIntChar(); // fill it backwards
}
return retVal;
}
int main()
{
RandomAtom<int> atom(GetTickCount());
for(int i = 0; i < 10; i++)
{
cout << randomItem(3, atom) << endl;
}
return 0;
}
This code generates the same 3 digit number 10 times.
Example usage of the class RandomAtom:
RandomAtom<int> atom(seed);
atom.randomIntChar(); // generate a random digit
Can someone help me find my error? Thanks.
I think it would help if you showed the implementation of the RandomAtom object.
ASKER
// File: RandomAtom.h
#ifndef _RandomAtom_H_
#define _RandomAtom_H_
#include "randInt.h" // defines M
#include <windows.h>
static const char* charAlphabet = "abcdefghijklmnopqrstuvwxy z";
static const int charModBase = 26;
static const int intModBase = 10;
template <class T>
class RandomAtom
{
public:
explicit RandomAtom(int seed = 1);
/* .......................... .......... .......... .....
Purpose : Constructor. Sets the seed
Restrictions : Should only be used with char
and int
Input : An integer for the seed
Description : RandomAtom is the constructor for
a template class which is specialized
for int and char. It generates a
random digit or lowercase letter.
Example Usage: RandomAtom<int> atom();
RandomAtom<char> atom();
.......................... .......... .......... ..... */
T randomIntChar();
/* .......................... .......... .......... .....
Purpose : To generate a random digit or
lowercase letter
Restrictions : Should only be used
with the int and char data types
Output : A random digit or int
Description : A member function which generates
either a random digit or random
lowercase letter
Example Usage: int i = atom.randomIntChar();
char c = atom.randomIntChar();
.......................... .......... .......... ..... */
private:
int state; // holds the seed
};
// Note: I had to place the implementation in this file
// because the compiler didn't allow a separate
// implementation file.
template <class T>
RandomAtom<T>::RandomAtom( int seed)
{
if(seed < 0)
seed += M;
state = seed;
if(state == 0)
state = 1;
}
template <class T>
T RandomAtom<T>::randomIntCh ar()
{
state = nextRand(state);
return (T)state;
}
// The specialized versions:
// char
template <>
class RandomAtom<char>
{
public:
explicit RandomAtom(int seed = 1);
T randomIntChar();
private:
int state;
};
template <>
RandomAtom<char>::RandomAt om(int seed)
{
if(seed < 0)
seed += M;
state = seed;
if(state == 0)
state = 1;
}
template <>
char RandomAtom<char>::randomIn tChar()
{
state = nextRand(state);
return charAlphabet[state % charModBase]; // return a lowercase letter from charAlphabet
}
// int
template <>
class RandomAtom<int>
{
public:
explicit RandomAtom(int seed = 1);
T randomIntChar();
private:
int state;
};
template <>
RandomAtom<int>::RandomAto m(int seed)
{
if(seed < 0)
seed += M;
state = seed;
if(state == 0)
state = 1;
}
template <>
int RandomAtom<int>::randomInt Char()
{
state = nextRand(state);
return state % intModBase; // return a digit
}
#endif
-------------------------- ---------- ---------- ---------- --
// File: randInt.h
#ifndef _randInt_H_
#define _randInt_H_
const int A = 48271;
const int M = 2147483647;
const int Q = M / A;
const int R = M % A;
int nextRand(int lastState);
#endif
-------------------------- ---------- ---------- --------
// File: randInt.cpp
#include "randInt.h"
int nextRand(int lastState)
{
int tmpState = A * (lastState % Q) - R * (lastState / Q);
if(tmpState >= 0)
return tmpState;
else
return tmpState + M;
}
#ifndef _RandomAtom_H_
#define _RandomAtom_H_
#include "randInt.h" // defines M
#include <windows.h>
static const char* charAlphabet = "abcdefghijklmnopqrstuvwxy
static const int charModBase = 26;
static const int intModBase = 10;
template <class T>
class RandomAtom
{
public:
explicit RandomAtom(int seed = 1);
/* ..........................
Purpose : Constructor. Sets the seed
Restrictions : Should only be used with char
and int
Input : An integer for the seed
Description : RandomAtom is the constructor for
a template class which is specialized
for int and char. It generates a
random digit or lowercase letter.
Example Usage: RandomAtom<int> atom();
RandomAtom<char> atom();
..........................
T randomIntChar();
/* ..........................
Purpose : To generate a random digit or
lowercase letter
Restrictions : Should only be used
with the int and char data types
Output : A random digit or int
Description : A member function which generates
either a random digit or random
lowercase letter
Example Usage: int i = atom.randomIntChar();
char c = atom.randomIntChar();
..........................
private:
int state; // holds the seed
};
// Note: I had to place the implementation in this file
// because the compiler didn't allow a separate
// implementation file.
template <class T>
RandomAtom<T>::RandomAtom(
{
if(seed < 0)
seed += M;
state = seed;
if(state == 0)
state = 1;
}
template <class T>
T RandomAtom<T>::randomIntCh
{
state = nextRand(state);
return (T)state;
}
// The specialized versions:
// char
template <>
class RandomAtom<char>
{
public:
explicit RandomAtom(int seed = 1);
T randomIntChar();
private:
int state;
};
template <>
RandomAtom<char>::RandomAt
{
if(seed < 0)
seed += M;
state = seed;
if(state == 0)
state = 1;
}
template <>
char RandomAtom<char>::randomIn
{
state = nextRand(state);
return charAlphabet[state % charModBase]; // return a lowercase letter from charAlphabet
}
// int
template <>
class RandomAtom<int>
{
public:
explicit RandomAtom(int seed = 1);
T randomIntChar();
private:
int state;
};
template <>
RandomAtom<int>::RandomAto
{
if(seed < 0)
seed += M;
state = seed;
if(state == 0)
state = 1;
}
template <>
int RandomAtom<int>::randomInt
{
state = nextRand(state);
return state % intModBase; // return a digit
}
#endif
--------------------------
// File: randInt.h
#ifndef _randInt_H_
#define _randInt_H_
const int A = 48271;
const int M = 2147483647;
const int Q = M / A;
const int R = M % A;
int nextRand(int lastState);
#endif
--------------------------
// File: randInt.cpp
#include "randInt.h"
int nextRand(int lastState)
{
int tmpState = A * (lastState % Q) - R * (lastState / Q);
if(tmpState >= 0)
return tmpState;
else
return tmpState + M;
}
Ah, no. Perhaps it had nothing to do with RandomAtom after all (I couldn't see any problem with it anyway).
I think the problem is with GetTickCount. GetTickCount returns a DWORD. If that is larger than an int, in your environment, you will wind up getting the bottom bytes as the seed, and, on a little-endian PC, those are the most significant bytes, and so won't change much.
I think the problem is with GetTickCount. GetTickCount returns a DWORD. If that is larger than an int, in your environment, you will wind up getting the bottom bytes as the seed, and, on a little-endian PC, those are the most significant bytes, and so won't change much.
ASKER
OK, instead of using GetTickCount I used the time() function for the system time.
RandomAtom<int> atom(int(time(0)));
It still is not working.
RandomAtom<int> atom(int(time(0)));
It still is not working.
ASKER
OK, instead of using GetTickCount I used the time() function for the system time.
RandomAtom<int> atom(int(time(0)));
It still is not working.
RandomAtom<int> atom(int(time(0)));
It still is not working.
ASKER
OK, instead of using GetTickCount I used the time() function for the system time.
RandomAtom<int> atom(int(time(0)));
It still is not working.
RandomAtom<int> atom(int(time(0)));
It still is not working.
ASKER
OK, instead of using GetTickCount I used the time() function for the system time.
RandomAtom<int> atom(int(time(0)));
It still is not working.
RandomAtom<int> atom(int(time(0)));
It still is not working.
ASKER
OK, instead of using GetTickCount I used the time() function for the system time.
RandomAtom<int> atom(int(time(0)));
It still is not working.
RandomAtom<int> atom(int(time(0)));
It still is not working.
ASKER
OK, instead of using GetTickCount I used the time() function for the system time.
RandomAtom<int> atom(int(time(0)));
It still is not working.
RandomAtom<int> atom(int(time(0)));
It still is not working.
I am not certain about any of this (which is why it is a comment and not an answer). However, time also returns a long, and casting it to an int is going to have the same result (whatever that is).
Perhaps you could inspect what seed RandomAtom is getting with a debugger or a print statement to see if we're on the right track or not.
Perhaps you could inspect what seed RandomAtom is getting with a debugger or a print statement to see if we're on the right track or not.
ASKER
Well I did output the results of int(time(0)) to the screen several times. It printed large numbers which would change, beginning with the last digit, everytime I ran it, such as: 1000334876. So I'm assuming this is the system time in seconds and that this isn't the problem.
The seed should be in the main.
Example:
#include <time.h>
int main()
{
srand( (unsigned)time( NULL ) );
RandomAtom<int> atom(GetTickCount());
for(int i = 0; i < 10; i++)
{
cout << randomItem(3, atom) << endl;
}
return 0;
}
Example:
#include <time.h>
int main()
{
srand( (unsigned)time( NULL ) );
RandomAtom<int> atom(GetTickCount());
for(int i = 0; i < 10; i++)
{
cout << randomItem(3, atom) << endl;
}
return 0;
}
In the above example, srand() takes the seed.
That's the only place you should have this seed, and there should only be one seed.
That's the only place you should have this seed, and there should only be one seed.
You're not using the rand() function any where in your code.
rand() is the function you need to add to your code in order to produce random numbers or char.
rand() is the function you need to add to your code in order to produce random numbers or char.
Example code:
using namespace std;
#include <time.h>
template <class T>
class foo
{
public:
T GetRandObject(void)
{
return rand();
}
};
int main()
{
srand( (unsigned)time( NULL ) );
foo<int> foo_int;
for(int i = 0; i < 10; i++)
{
cout << foo_int.GetRandObject() << endl;
}
foo<char> foo_char;
for(int a = 0; a < 10; a++)
{
cout << foo_char.GetRandObject() << endl;
}
return 0;
}
using namespace std;
#include <time.h>
template <class T>
class foo
{
public:
T GetRandObject(void)
{
return rand();
}
};
int main()
{
srand( (unsigned)time( NULL ) );
foo<int> foo_int;
for(int i = 0; i < 10; i++)
{
cout << foo_int.GetRandObject() << endl;
}
foo<char> foo_char;
for(int a = 0; a < 10; a++)
{
cout << foo_char.GetRandObject() << endl;
}
return 0;
}
ASKER
I tried the first example you gave, but still the same problem. I looked at your sample code though, and in your class you use rand() whereas in my class I have my own randomizing code which is taken from my textbook. Maybe that's why srand() isn't working?
>>in my class I have my own randomizing code which is
>>taken from my textbook.
I couldn't find any random-ness inside that code. I could not identify anything that looked like a random function.
What book did you take this out of?
>>taken from my textbook.
I couldn't find any random-ness inside that code. I could not identify anything that looked like a random function.
What book did you take this out of?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
The files randInt.h and randInt.cpp contain the random number code. The code for these files is listed at the bottom of my very first posting. This is taken from section 10.4.1 of <u><b>Data Structures & Algorithm Analysis in C++</b></u>, second edition, by Mark Allen Weiss.
ASKER
I mean the bottom of my second posting.