Re: unique numbers using srand( ) and rand( ) functions in C++[ caution long post]

From: Arthur J. O'Dwyer (ajo_at_nospam.andrew.cmu.edu)
Date: 12/08/03


Date: Mon, 8 Dec 2003 13:04:18 -0500 (EST)


On Mon, 8 Dec 2003, Robert Stankowic wrote:
>
> "August1" <anthonyb_nc@hotmail.com> schrieb...
> > A handful of articles have been posted requesting information on how
> > to use these functions in addition to the time() function as the seed
> > to generate unique groups (sets) of numbers - each group consisting of
> > 6 numbers - with a total of 50 groups of numbers.

> > Just copy it and paste it and you'll get one way for executing this
> > exercise.

<snip all the way down to Robert's last version>

  You forgot a couple of things; e.g., the array bounds on array
'one_tip' should be specified by GROUP_SIZE, not the literal number
6. Also, IANAC++G, but I thought that C++ style preferred 'const'
over '#define' in most contexts?
  And just in general, this is a silly way to approach the problem.
Why write to a file and then read the data right back in, when you
could output the data directly as you were writing them?
  Anyway, my couple of nits changed below:

> #include <iostream>
> #include <fstream>
> #include <ctime>
> #include <cstdlib>
>
  using namespace std;
>
>
> #define NUM_GROUPS 50
> #define GROUP_SIZE 6
> #define NUM_COLUMNS 3
>
> enum
> {
> SUCCESS,
> OPEN_OUT_FAILED,
> OPEN_IN_FAILED,
> WRITE_FAILED,
> READ_FAILED
> };
>
> int WelcomeAndInit(ofstream& send2file, ifstream& readfile)
> {
> cout << " Lottery Numbers" << endl << endl
> << "This program opens the data file \"T8Be08.dat\" and then stores"
> "groups of" << endl
> << "lotto numbers that have 6 unique numbers to a group in the data"
> "file." << endl
> << "There are 50 groups of numbers. The groups of numbers are"
> " displayed to the" << endl
> << "screen - 3 groups per line." << endl << endl;
>
> srand(time(NULL));

 /* I think the above line is missing a cast that is required in
    C++. (RJH suggested as much in his post.) Confirm?
  */

> send2file.open("T8Be08.dat", ios::out);
> if(send2file.fail())
> {
> return OPEN_OUT_FAILED;
> }
> readfile.open("T8Be08.dat", ios::in);
> if(readfile.fail())
> {
> send2file.close();
> return OPEN_IN_FAILED;
> }
> return SUCCESS;
> }
>
>
> int WriteNumberFile(ofstream& send2file)
> {
> int one_tip[GROUP_SIZE] = {0};
>
     for (int group=0; group < NUM_GROUPS; ++group)
> {
        /* generate a group of numbers */
        int lower_bound = 1;
        int upper_bound = 9;
        for (int i=0; i < GROUP_SIZE; ++i)
> {

#define RND0(m) (int)(rand() / (RAND_MAX+1.) * m)
           one_tip[i] = lower_bound + RND0(upper_bound - lower_bound + 1);
#undef RND0

/* Note that the original code had 'rand() % m' to generate numbers
 * in the range [0, m), which is not only a Bad Thing, but it's also
 * a FAQ. And since I assume the OP's whole point was that he was
 * a l33t r4nd hax0r, I don't know why such an elementary problem
 * was left in.
 */

> lower_bound = upper_bound + 1;
> upper_bound = upper_bound + 9;

/* It would also be nice to do away with these two variables, but
 * that would require more work. Note that the groups have a range
 * of (10k) to (10k+9), except for the first group, which has the
 * range 1 to 9 (*not* 0 to 9).
 */

> if (i == GROUP_SIZE-1)
> {
> /*we are done with one group, so we write it to the file*/
              for (int j=0; j < GROUP_SIZE; ++j)
> {
> if (j == GROUP_SIZE-1)
                   send2file << one_tip[j] << endl;
> else
                   send2file << one_tip[j] << '#';

> if (send2file.fail())
                   return WRITE_FAILED;
> }
> }
> }
> }
> send2file.close();
> return SUCCESS;
  }
>
>
> int ReadAndDisplayFile(ifstream& readfile)
> {
> int one_tip[GROUP_SIZE] = {0};
>
> for (int group=0; group < NUM_GROUPS; ++group)
> {
> for(int i=0; i < GROUP_SIZE; ++i)
> {
> readfile >> one_tip[i];
> readfile.ignore(1);
> if (readfile.fail())
> {
> return READ_FAILED;
> }
> cout << one_tip[i] << " ";
>
> if(i == GROUP_SIZE-1)
> {
> cout << " ";
> }
> }
> /*if 3 groups of lotto numbers are on the output screen,
> go to next line*/
> if ((group+1) % NUM_COLUMNS == 0)
          cout << endl;
> }
> cout << endl;
>
> readfile.close();
> return SUCCESS;
> } /* ReadAndDisplayFile */
>
>
>
> void OnError(int err_code)
> {
     switch (err_code)
> {
> case OPEN_OUT_FAILED:
> cout << "The output file could not be opened" << endl;
> break;
> case OPEN_IN_FAILED:
> cout << "The input file could not be opened" << endl;
> break;
> case WRITE_FAILED:
> cout << "There was an error writing to the output file" << endl;
> break;
> case READ_FAILED:
> cout << "There was an error reading from the input file" << endl;
> break;
> }
     exit(EXIT_FAILURE);
  }
>
>
> int main()
> {
> ofstream send2file;
> ifstream readfile;
> int result;
>

/* Robert's original 'main' code was missing a few error checks,
 * which was odd, given that *he'd* put in the error-checking
 * enums in the first place. :) Fixed. Note that OnError()
 * now quits the program.
 */

     if ((result = WelcomeAndInit(send2file, readfile)) != SUCCESS)
       OnError(result);
     if ((result = WriteNumberFile(send2file)) != SUCCESS)
       OnError(result);
     if ((result = ReadAndDisplayFile(readfile)) != SUCCESS)
       OnError(result);
> return EXIT_SUCCESS;
  }

> /*****************************
> This is still far away from being perfect.
> Comments appreciated :)
> *****************************/

HTH,
-Arthur



Relevant Pages

  • Re: Request critique of first program
    ... Returns a pointer to an asplit_result struct (unless unable to ... Success is indicated by SUCCESS, ... const char *out_file_b, ... const long int num_lines); ...
    (comp.lang.c)
  • Re: Interpreting command lines.
    ... int ConsolidateStrArray(char **ArrayPtr, ... return Success; ... (OldRows + NumRowsToAdd) ... Array = NULL; ...
    (comp.lang.c)
  • Request critique of first program
    ... long int num_rem_lines; ... Returns a pointer to an asplit_result struct (unless unable to ... Success is indicated by SUCCESS, ... Read from standard input, writing first 100 lines to output1 ...
    (comp.lang.c)
  • Request critique of first program
    ... long int num_rem_lines; ... Returns a pointer to an asplit_result struct (unless unable to ... Success is indicated by SUCCESS, ... Read from standard input, writing first 100 lines to output1 ...
    (comp.lang.c)
  • Copy and Paste in a DataGridView with Ctrl-C and Ctrl-V
    ... private bool _shiftDown = false; ... const int WM_KEYDOWN = 0x0100; ... handledMessage = PerformPaste; ... bool success = false; ...
    (microsoft.public.dotnet.framework.windowsforms)