3 number Random generator

closed account (ozh0oG1T)
Hello!! I’m currently struggling on my program with changing the function of getNumbers(). What I need my program to do is generate 3 random numbers ranging from 4 to 401 within the function call. So far I have not figured out the correct form with comments included. Any help would be much appreciated

[code]

*/
#include <iostream> // preprocessor directives
using namespace std; // namespace statement
// function prototypes
void getNumbers(int &, int &, int &);
void showMax(int);
int Findlargest (int, int, int);

int main() { // main() function - the driver
int no1, no2, no3, maxOf3; // local variables are defind inside { }
// local variables are used only in { }
getNumbers(no1, no2, no3);
maxOf3 = Findlargest(no1, no2, no3);
showMax(maxOf3);
return 0;
}
// A function that gets three numbers from the user.
void getNumbers(int &one, int &two, int &three) {
cout << "Enter 3 integers: ";
cin >> one >> two >> three;
cout << endl;
}

// A function displays the largest number among the
// three input numbers.
void showMax(int someNumber) {
cout << someNumber << " is the largest";
}

// A subprogram that finds the largest one and place it in Max.
int Findlargest (int no1, int no2, int no3) {
int max;
if ((no1 > no2) && (no1 > no3))
max = no1;
else if (no2 > no3)
max = no2;
else
max = no3;
return max;
}

[code end]


So far I have written 3 function calls that I believe would work but my teacher said it wasn’t correct

1. rand () % 4 + 401
2. rand () % 401 - 397
3. rand () % 405
Last edited on
Please edit your post and add code formatting by adding [code] and [/code] around your program.
Last edited on
A very simple example, since c++ random is a slightly complicated tool to set up.

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
#include<random>
#include<iostream>
using namespace std; //this is a bad habit but just going with your flow

void getNumbers(int &one, int &two, int &three, int seed = 0) 
{   
  static default_random_engine generator; //static keeps the variable even if funciton ends. 
  //we want static to keep the random generating stream intact. 
  //ideally you would make a random number function and split it out of this one
  //but its a simple assignment so all in one function is ok for today. 
  static uniform_int_distribution<int>  dp = uniform_int_distribution<int>(4,401);
  if(seed)
  {
    generator.seed(seed);
	dp(generator); //my compiler has a bug that first number is 0, this skips it. 
  }
  one = dp(generator);
  two = dp(generator);
  three = dp(generator);   
}
 
 int main()
 {
     int a,b,c;
	 getNumbers(a,b,c, time(0)); //time 0 is a common seed for simple random streams. 
	 cout << a<< endl << b << endl << c << endl;

      // you normally only want to seed it one time, after the first call you can use 
	 getNumbers(a,b,c); 
//I am in the habit of resetting my streams to get the same N numbers multiple times.
//If you do not need this, you can remove seed as a param and do it inside with a once..
// static bool once = true;
// if (once) {generator.seed(time(0)); dp(generator);  once = false;}
//anyway, a handful of handy things in here if you haven't seen them.. static, random, default value params 
 }

Last edited on
An even simpler (and much less sophisticated) approach might be something 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
24
25
26
27
28
29
30
31
#include <iostream>
#include <cstdlib>

int generateRandomNumber()
{
	const unsigned short int LOWER_BOUND = 4;
	const unsigned short int UPPER_BOUND = 401;

	return LOWER_BOUND + rand() % UPPER_BOUND;

	return rand()%(UPPER_BOUND-LOWER_BOUND + 1) + LOWER_BOUND;
}

void getNumbers(int& a, int& b, int& c)
{
	a = generateRandomNumber();
	b = generateRandomNumber();
	c = generateRandomNumber();
}

int main()
{
	srand(time(0));

	int a, b, c;
	getNumbers(a, b, c);

	std::cout << a << " " << b << " " << c << " ";

	return 0;
}


I'd err on the side of Jonnin's code, since it's worth learning the standard random library, but depending on what you need the code for, it's OK to know this "solution" as well.

https://stackoverflow.com/questions/53040940/why-is-the-new-random-library-better-than-stdrand
Last edited on
@Aaron: your example has unrelated issue:
1
2
3
4
5
6
7
8
9
int generateRandomNumber()
{
	const unsigned short int LOWER_BOUND = 4;
	const unsigned short int UPPER_BOUND = 401;

	return LOWER_BOUND + rand() % UPPER_BOUND;
	// function will never reach this far, because the 'return' above ends it
	return rand()%(UPPER_BOUND-LOWER_BOUND + 1) + LOWER_BOUND;
}


The modern C++'s std::uniform_int_distribution<int>(4, 401) is very clear, it can generate any number from range [4, 401].
Note the inclusive limits; both 4 and 401 could be returned.

The rand () % N returns from range [0, N), that is from range [0, N-1]. While we can see that we can get exactly N different values, we must do the -1 to see the largest possible value.

Lets look at:
rand () % 401 - 397
The smallest possible value is 0 - 397. That is -397
The largest possible value is 400 - 397. That is 3

The [-397, 3] is not same as [4, 401].


This is a math problem. How to choose X and Y for rand() % X + Y such that:
1
2
0 + Y == 4
(X-1) + Y == 401
return LOWER_BOUND + rand() % UPPER_BOUND;
// function will never reach this far, because the 'return' above ends it
return rand()%(UPPER_BOUND-LOWER_BOUND + 1) + LOWER_BOUND;


Whoops, thats my bad. I was playing around the formulas and forgot to delete the first line.

Thanks for spelling out the differences between these two approaches!
splitting it into 2 functions is better design (I said that but its worth noting again, and the above did that). I recommend playing with <random> to make yourself a couple of functions (or a class if you know them) that you can reuse, as this comes up over and over esp in schoolwork.
And then we have the bare-bones approach which solves the immediate problem but also shows why a couple of more 'sophisticated' approaches give greater flexibility and potential for re-use in other programs if the bounds were general and repeated code was removed.

One embellishment not mentioned AFAICS is the use of array-like data structures instead of separate variables one, two, three. Perhaps not covered yet :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <ctime>

void get3Randoms(int&, int&, int&);

int main()
{
    int one{0}, two{0}, tri{0};
    
    get3Randoms(one, two, tri);
    std::cout << one << '\t' << two << '\t' << tri << '\n';
    
    return 0;
}

void get3Randoms(int& a, int& b, int& c)
{
    srand (time(NULL));
    
    a = rand() % 397 + 4; // rand => 0 - 397 inc, Add 4 => 4 - 401 inc
    b = rand() % 397 + 4;
    c = rand() % 397 + 4;
};
If there weren't other restrictions then one could be more generic:
1
2
3
4
5
6
7
8
9
10
11
12
// returns random number from range [4, 401]
int getRandom();

int main()
{
    srand ( time(NULL) ); // if using rand()
    int one{0}, two{0}, tri{0};
    one = getRandom();
    two = getRandom();
    tri = getRandom();
    std::cout << one << '\t' << two << '\t' << tri << '\n';
}

The get3Random() does a very specific job.
With getRandom() we can get 1, 2, 3, 4, ... random numbers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <random>
#include <ctime>
using namespace std;

int L = 4, H = 401, RANGE = H - L + 1;
mt19937 gen( time( 0 ) );
uniform_int_distribution<int> dist( 0, RANGE * RANGE * RANGE - 1 );

int getRand() { return dist( gen ); }

int main()
{
   int n = getRand();
   cout << L + ( n / RANGE / RANGE ) << ", " << L + ( n / RANGE ) % RANGE << ", " << L + n % RANGE << '\n';
}


It doesn't scale very well, though!
Last edited on
Topic archived. No new replies allowed.