Random numbers and Vectors

Pages: 12
Ok, so I have an assignment, which is designed to see if I can implement the work into a class. That's actually the easy part, but I'm having problems trying to figure out how to do the actual work. We need to generate 250 random numbers using a vector. It's been a long time since I've had to use a random number generator, and I can do it without sticking to the requirements of the assignment just fine, but I can't seem to get anything to work when I follow the instructions. I need some help trying to figure out how to do this, so if anyone can help me out and walk me through this I'd appreciate it. Here's the assignment...


The random number generator provided in C++ is really pseudo-random number generator. What this means is that if you examine the output you will find that the numbers repeat in a pattern. I want you to create a better random number generator.

In object oriented programming what you really want to do is reuse code. Since the rand function does a great deal of what we desire, we can use it, and then simply add functionality to make it more efficient. The class you are going to be creating in this assignment is called Random and it will be loosely based on the Java Random class.

Here is the functionality

Constructor Summary

Random(); - Default constructor

Random(double min, double max); - generates random numbers between min and max.

Random(int seed); - seed the random number generator

Function Summary

int nextInt() - Returns the next random number as an int

double nextDbl() - Returns the next random number as a primitive double

void setRange(double min, double max) - Sets the rage and recreates random numbers


Specifics

Basically, this is a wrapper around the function rand. You will put a vector in your data section to hold 250 primitive double values. When one of the constructors is called you will clear the vector and fill it with new random doubles. For this you should have a private function called fillVect which will generate random doubles in whatever range is specified.. Once the vector is filled you will want to shuffle the values in the vector around. I will leave it up to you to determine how to shuffle the vector but it may be easy to simply swap values at two random indexes a bunch of times. This function should be called shuffle and should be defined as private.

To generate random doubles in a range you can use the following algorithm:

double r = (((double) rand() / (double) RAND_MAX) * (max - min)) + min ;

Where min and max are double values passed into the private function called fillVect. RAND_MAX is a constant that is added when you include iostream. You do not need to do anything to use it.

Constructors

The default constructor and the constructor that takes the seed should simply fill the vector with numbers in the range of 0 to RAND_MAX.

All constructors except the constructor that takes the seed will use the time function to seed the random number generator.

The constructor that takes seed should pass the value to srand for seeding.

Functions

The next functions should return the next value in the vector as whatever type specified.

Please note that when you have gone through 90% or more of the vector you should reshuffle and start from the beginning

The setRange functions should clear the vector and generate new random numbers for the vector. The vector should also be shuffled once it has been filled.

Finally, try to avoid using literal values. You know that you should use 250 numbers and you need to reshuffle at 90%. It would be best to use constants to define these values.




I have no idea how your supposed to clear a vector and reset it with random numbers, or how to apply it to the random number generator that were required to use. I can use a vector to make random numbers:

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
	double r (int i) { return std::rand()%i;}

int main ()
{

  srand ( unsigned ( std::time(0) ) );
  vector <int> cj;

  
  for (int i=1; i<250; ++i) cj.push_back(i*.9); 
  

  std::random_shuffle ( cj.begin(), cj.end() );


  std::random_shuffle ( cj.begin(), cj.end(), r);


 
  for (std::vector<int>::iterator go = cj.begin(); go != cj.end(); ++go)
    std::cout << ' ' << *go;

  std::cout << '\n';

  return 0;
}


or even

1
2
3
4
5
6
7
8
9
10
11
          const double BIG=250;

	  srand( static_cast<unsigned> (std::time(NULL)) );

          vector<double> cjVect(BIG, 1);

	  partial_sum(cjVect.begin(), cjVect.end(), cjVect.begin());

	  random_shuffle(cjVect.begin(), cjVect.end());

	  copy(cjVect.begin(), cjVect.end(), ostream_iterator<double> (cout, " "));


I just cannot for the life of me get the double r = (((double) rand() / (double) RAND_MAX) * (max - min)) + min ; to work with a vector. Anyone have any ideas on how I can do this?
Last edited on
Hi, check out this link. It is obviously not a direct translation of how to do this, but it should give a little help of understanding vectors on a more deeper level.

http://www.oopweb.com/CPP/Documents/ThinkCScpp/Volume/chap10.htm
Yeah, I've seen that, but thanks for the advice!

I'm still trying to sort out how to get the double r = (((double) rand() / (double) RAND_MAX) * (max - min)) + min ; to play nice with my vector, It's frustrating beacuse I can do most of the requirements without the formula offered by the teacher.

Another good question would be how do you check to see if 90% of the numbers have been generated so you can reset everything?
Last edited on
If I want to shuffle the vector, I assume I have to use this:

 
random_shuffle(vectorName.begin(), vectorName.end());


Is that correct? I still have no clue about seeing if it's hit 90% though.
Well, I'm generating random numbers, but I'm not all that sure I'm doing it correctly, at least as far as the requirements go. Anyone feel like having a look and telling me if I'm at least on the right track?

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
#include<iostream>
#include "random.h"

Random::Random()
{
	
	for (int i=1; i<250; ++i)
	{
		srand((unsigned)time(0));
		&Random::setRange;
		fillVect.push_back(i);
	}
	&Random::nextInt;
	random_shuffle ( fillVect.begin(), fillVect.end() );
	for (vector<double>::iterator go = fillVect.begin(); go != fillVect.end(); ++go)

    cout << ' ' << *go;

    cout << '\n';

}

Random::Random(double min, double max)
{
		

}
Random::Random(int seed)
{	
	srand((unsigned)time(0));
    seed = rand(); 
    seed %= 250, 1; 
}

void Random::setRange(double min, double max)
{
	
double r = (((double) rand() / (double) RAND_MAX) * (max - min)) + min ;

}

int Random::nextInt()
{
	int r = rand() % 250;
return r;
}
You only need to call srand once as this re-seeds it, calling it more than once is pointless and means you cannot reproduce a string or random numbers.

1
2
3
4
5
6
7
srand((unsigned)time(0));
fillVect.clear();

for (unsigned i = 0; i < 250; ++i) {
  double r = (((double) rand() / (double) RAND_MAX) * (max - min)) + min ;
  fillVect.push_back(i);
}


You should call an Init(double min, double max) method from your constructors, then you can use this from the setRange() method as well. The above snippet of code should help :)
I've tried that before, (minus the fillVect.clear), every which way from Sunday, and every time it just pops out a blank page. I've thrown it into my Random(double min, double max), and even assigned const's to min and max, but it always comes out blank. Maybe I'm just missing something, but I don't see where the "r" is being initialized and used.
The code &Random::setRange; takes the address of the setRange member and discards it. Likewise with &Random::nextInt;. Iow, these expressions do nothing at all.

Constructors
The default constructor and the constructor that takes the seed should simply fill the vector with numbers in the range of 0 to RAND_MAX.
All constructors except the constructor that takes the seed will use the time function to seed the random number generator.
The constructor that takes seed should pass the value to srand for seeding.


The setRange member doesn't set a range. In fact, it doesn't do anything. It assigns a local variable a value which is then discarded. The code mentioned in the assignment was meant to be in the private member function fillVect. Not that fillVect is the name of a private function, not a data member of the class. It isn't specified what the vector data member should be called, so I'm going to call it something silly like: numbers.

1
2
3
4
5
6
7
8
9
10
void Random::fillVect( double min, double max )
{
    numbers.clear() ;

    for (unsigned i = 0; i < 250; ++i) 
    {
        double r = (((double) rand() / (double) RAND_MAX) * (max - min)) + min ;
        numbers.push_back(r);
    }
}


As per your assignment, you should not be calling srand() except in one constructor which also takes the seed as an argument (so you won't be using srand(time(0)) in the constructor.)

You really need to pay more attention to the specifics of the assignment (and so did I.)

The default constructor and the constructor that takes the seed should simply fill the vector with numbers in the range of 0 to RAND_MAX.


1
2
3
4
5
6
7
8
9
10
11
12
// default constructor:
Random::Random()
{
    srand(time(0)) ;
    fillVect(0.0, RAND_MAX) ;
}

Random::Random( unsigned seed )
{
    srand(seed) ;
    fillVect(0.0, RAND_MAX) ;
}


Hopefully that gives you a little working code to play with.

Last edited on
HA! I didn't even realize that fillVect wasn't supposed to be the vector, how did I miss that? I've been so concerned on trying to just make it all work in main first (to test that I can even remember how to make random numbers), and then go back and pop it into place in regards to the class that my heads been out in la-la land. I've gone through and just started putting everything where it should be, or at least what I have at the moment.

I don't have a clue as to what nextInt and nextDouble should be doing. I know what it says in the instructions, but thoes two are over my head at the moment. Here's what I have so far:

random.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
#ifndef _RANDOM
#define _RANDOM
#include <iostream>
 #include <vector>
 #include <cstdlib>
 #include <ctime>
 #include <algorithm>
 #include <iterator>
 #include <numeric>
using namespace std;

using std::istream;
using std::ostream;

const double max = 250;
const double min = 1;

class Random
{
private:
vector <double> myVect;
void fillVect(double min, double max);
void shuffle();

public:

Random();  //- Default constructor 
Random(double min, double max);  //- generates random numbers between min and max.
Random(int seed);   //- seed the random number generator
int nextInt();  //- Returns the next random number as an int
double nextDbl(); //- Returns the next random number as a primitive double
void setRange(double min, double max); //- Sets the rage and recreates random numbers
void printout();
};

#endif


random.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
#include<iostream>
#include "random.h"

Random::Random()
{
    srand(unsigned(time(0))) ;
    setRange(1.0, RAND_MAX) ;
}

Random::Random(int seed)
{
    srand(seed) ;
    setRange(1.0, RAND_MAX) ;
}

Random::Random(double min, double max)
{

}

void Random::setRange(double min, double max)
{

}

void Random::fillVect(double min, double max)
{
  
	myVect.clear();

    for (unsigned i = 0; i < 250; ++i) 
    {
        double r = (((double) rand() / (double) RAND_MAX) * (max - min)) + min;
        myVect.push_back(r);	
    }
	
}

void Random::shuffle()
{
 random_shuffle ( myVect.begin(), myVect.end() );
}

int  Random::nextInt()
{
	return 0;
}

double Random::nextDbl()
{
	return 0;
}

void Random::printout()
{
	for (vector<double>::iterator go = myVect.begin(); go != myVect.end(); ++go)

    cout << ' ' << *go;

	cout << '\n';
}


I'm new to programming, (I bought a book to try it out), and I've already covered random numbers from the book, and am trying out vectors. I know that this is set up in a class, with a header and cpp file where your supposed to have functions that do certain things, and I tried out what you have so far, but nothing prints out. I am going to assume your not done with the program from what I've read, but I would like to see what it looks like when your done if that's ok. Also, I see that you have your function setRange, which has nothing inside of it, but you call it up in Random, and assign values to it. Is that the correct way to do that, or should something else be put inside the setRange function?
Yeah, it's still a work in progress. I can generate random numbers pretty easy, but they way I'm being asked to do it for this is confusing the crud out of me. There's a lot of what required that I don't understand. I've gone through three books, and tons of websites trying to find something even remotely similar that could give me a clue as to what I'm missing here, but so far no luck. As for the print thing, I was just trying that out, and I'm not too sure of what to use to print. Right now I'm just trying to figure out how to analyze the vector to see if it's hit 90%, I am totally clueless on that one. When I have it up and running though, I would be happy to let you see it, and hopefully by then, I can explain what I've done.
Last edited on
One thing that I feel I should point out quickly about your header file, is your inclusion of #include <iostream> and using namespace std; It is fine to have #include <iostream> just be sure not to include it elsewhere in your project and also refrain from putting using namespace std; in your header file. Doing so pollutes the namespace and doesn't allow for other namespaces to be used.

EDIT: Also, why are you doing things in the range of 1.0 - RAND_MAX? The instructions state in the range from 0 - RAND_MAX.
Last edited on
Thanks for the tip, I didn't know that putting namespace in the header would do that. As for the 1.0, I was playing around with the numbers attempting something that ended up not working, but I've since changed it back to 0.0. Right now, I'm just looking up what I can do code wise to get this thing to actually pump out numbers. So far everything I try just gives me nothing.
When I print out these number in main, does it make more sense to make the print function in my random.cpp file, and then just call it up in main, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Random::printnum()
{

    for (int i = 0; i < 250; ++i)
    {

        cout << myVect[i] << endl; // function I have inside my random.cpp
    }

//main

Random x;

x.printnum(); //prints ints

//OR

Random x(1, 250)

x.printnum() // prints doubles

}

When I print out these number in main, does it make more sense to make the print function in my random.cpp file, and then just call it up in main, like this:

It would make sense not to have a print function as part of the class. The purpose of the class is to act as a random number generator, not print stuff.

You need another class data member, maybe called index.

1
2
3
4
5
6
7
8
9
int Random::nextInt()
{
    return static_cast<int>(myVect[index++]) ;
}

double Random::nextDbl()
{
    return myVect[index++] ;
}


Note that these functions should serve as triggers for your 90% rule. (When index is 90% of myVect.size().)

As an aside, the 90% rule doesn't make any sense to me. Using all of the generated numbers, then generating new ones would make more sense to me, but we do what they tell us, eh?
I decided on going this route for the main, and it ends up printing first a double, then an int, and then repeating the process the 250 times.

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{

    Random xx(1,RAND_MAX);
	Random x;

	for(int i = 0; i < 250; i++)
		{
		cout<< xx.nextDbl()<<endl;
		cout<< x.nextInt()<<endl;		
		}    

};


I have it all up and running now, but can't post the code until after we turn it in, but this one was a doozey.

And for thoes wondering, I did manage to figure out the whole 90% thing, roughly translated, I did this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
double Random::nextDbl()
{
    double x;

    // I did an if statement here checking to see if it hit 90%
		{
        x = vector[a];  // a is an int in the header
        a++;
        return x;
		}

	else
		{
    // I cleared x, shuffled the numbers, and then repeated what I did up above

         return x;
		}
}


and I had to add this to the constructors, beacuse they would generate a double number, like 234.3, and then the following int would be 234, which didn't seem right

1
2
3
4
5
6
Random::Random()
	{
    myVect.resize(maxNum);   
    srand(unsigned(time(NULL)));
    fillVect(0.0, RAND_MAX) ;
	}


and the numbers I get, (some of them at least):


9395
10681.7
29645
11718.6
17513
18902.4
11214
18274.4
30774
10397.7
32638
29462.1
17802
25810.2
131
18172.4
20345
14884.5
19012
19953.4
10691
21941.3
23659
21029.4
14024
522.984
21549
20743.4
9493
25050.2
19300
14713.6
10867
1746.95
32281
Last edited on

It would make sense not to have a print function as part of the class. The purpose of the class is to act as a random number generator, not print stuff.

You need another class data member, maybe called index.

1
2
3
4
5
6
7
8
9
9	int Random::nextInt()
{
    return static_cast<int>(myVect[index++]) ;
}

double Random::nextDbl()
{
    return myVect[index++] ;
}


Note that these functions should serve as triggers for your 90% rule. (When index is 90% of myVect.size().)

As an aside, the 90% rule doesn't make any sense to me. Using all of the generated numbers, then generating new ones would make more sense to me, but we do what they tell us, eh?


So let me try and understand this. Your saying I should create another data member to the class, say we call it index. Inside of the index function, is where I would call up the work that scans the vector, and pumps out numbers, up to 225 (90% of 250), shuffle it when it hits that number, and then call that up inside my nextInt. Would I then need another member to handle the doubles? And how does that bypass the need to print?

AS for the 90% rule, yeah, it's an assingment. Half the stuff we do just makes me shake my head sometimes, but the point is to teach us how to do this stuff, even if we don't necessarily need it for whatever work is being done. Can't learn it if you don't do it I suppose.
So let me try and understand this. Your saying I should create another data member to the class, say we call it index.

Yes. In your latest code snippet it looks like you've done something similar with a global variable named a if I understood your post correctly. The only problem with a global variable is that all instances of Random will share the same one, and if you ever wanted different instances of Random to store a different number of random numbers, that would make things rather awkward.

Inside of the index function, is where I would call up the work that scans the vector, and pumps out numbers, up to 225 (90% of 250), shuffle it when it hits that number, and then call that up inside my nextInt.
index would be a data member, not a function. What I was suggesting is that nextInt and nextDbl is the place to worry about/implement the 90% rule, much as you indicate you did in your last code snippet.

Would I then need another member to handle the doubles?

No.

And how does that bypass the need to print?

It's completely unrelated to the need to print, which is easily done from main from outside the class.
I Pm'd you a copy of my code, since I can't post it. That ought to give you a better idea of what I did.
"double Random::nextDbl()
{
double x;

// I did an if statement here checking to see if it hit 90%
{
x = vector[a]; // a is an int in the header
a++;
return x;
}

else
{
// I cleared x, shuffled the numbers, and then repeated what I did up above

return x;
}
}"


Now why not compress the code down to something of this nature?
double Random::nextDbl(){

// If statement to see if index has has hit 90%
// If greater, reset index to 0
// And use just one if statement and then return vect[index++]
Pages: 12