2

Im using this function:

int rand2(int lim)
{
        static long a = 1;  // could be made the seed value
        a = (a * 32719 + 3) % 32749;
        return ((a % lim) + 1);
}

to get a stack of random number, it work fine but each time i launch this function I will have the same stack of number, so I want to use the time() system function to have each time a different stack

int rand3(int lim, int dat_time)
{
  static int a = dat_time; // could be made the seed value                                                       
  a = (a * 32719 + 3) % 32749;
  return ((a % lim) + 1);
}

then i give one time the time() of my computer since the variable a is a static

int             main()
{
  int           rd;
  time_t        timee;
  int           seed;

  timee = 0;
  timee = time(timee);
  seed = timee;
  while(42)
    {
      rd = rand3(52, seed);
      printf("%d\n", rd);
      getchar();
    }
}

Then i get an error saying dat_time is not a constant, but since i use it one time I dont get why

Saxtheowl
  • 4,136
  • 5
  • 23
  • 32
  • 4
    A similar question [why compiler restricts global variable always to be intialized by constant value?](http://stackoverflow.com/questions/19130321/why-compiler-restricts-global-variable-always-to-be-intialized-by-constant-value) –  Oct 02 '13 at 09:01
  • I know of no C compiler that would allow this code. Did you even try to compile it? If so, you need a new compiler. – Lundin Oct 02 '13 at 09:31

4 Answers4

3

Static storage duration variables are initialised before any code starts running and they must be initialised with an expression calculable at compile time.

That means no using variables that can't be determined until run-time to initialise them. If you removed the static, the error would disappear but then you're going to re-seed the random number generator every time you call it.

You really should initialise the random seed once before asking for the first random number (as in srand()/rand() from the C standard library), and then use your random function to cycle through the values in the sequence. That could be done with something like:

int rand4 (int numLimit) {
    static int randSeed, needsInit = 1;
    if (needsInit) {                      // This bit only done once.
        randSeed = time(0);
        needsInit = 0;
    }
    randSeed = (randSeed * 32719 + 3) % 32749;
    return (randSeed % numLimit) + 1;
}

A typical implementation of srand()/rand() is along the lines of:

// RAND_MAX assumed to be 32767.
static unsigned long int next = 1;
void srand(unsigned int seed) { next = seed; }
int rand(void) {
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}

in its own source file so that the next seed is hidden from view. This follows the expected behaviour that calling rand() without first calling srand() is the same as if you had called srand (1).


And, based on your comment that you need a certain number of calls to generate all the numbers from 1 to 52, it sounds like you're using this to generate a randomised deck of cards. If that's the case, there's a better way to do it than generating a random number and throwing away those you've already seen.

That solution deteriorates quickly as the size of the remaining deck gets smaller and smaller. For an O(1) time and space solution, use the Fisher-Yates shuffle.

The basic algorithm is to use an unsorted list and simply swap the final element with a randomly chosen one, reducing the list size by one:

dim n[N]                  // gives n[0] through n[N-1]

for each i in 0..N-1:     // initialise them to their indexes
    n[i] = i              // (use i+1 for 1-10 instead of 0-9).

nsize = N                 // starting pool size
do N times:
    i = rnd(nsize)        // give a number between 0 and nsize-1
    print n[i]
    nsize = nsize - 1     // these two lines effectively remove the used number
    n[i] = n[nsize]

The numbers generated by that are:

<------ n[] ------>
0 1 2 3 4 5 6 7 8 9  nsize  rnd(nsize)  output
-------------------  -----  ----------  ------
0 1 2 3 4 5 6 7 8 9     10           4       4
0 1 2 3 9 5 6 7 8        9           7       7
0 1 2 3 9 5 6 8          8           2       2
0 1 8 3 9 5 6            7           6       6
0 1 8 3 9 5              6           0       0
5 1 8 3 9                5           2       8
5 1 9 3                  4           1       1
5 3 9                    3           0       5
9 3                      2           1       3
9                        1           0       9
Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Okay, look great, and for the information I need < 300 call to get 52 different random number between them, i needed > 50000000 on my previous test for all 52 before ^^ – Saxtheowl Oct 02 '13 at 09:10
  • Thanks for the link, I wil stay with my previous funct since the ressources recquirement is very little – Saxtheowl Oct 02 '13 at 09:26
  • No problems, @Saxtheowl, just providing that as an option. – paxdiablo Oct 02 '13 at 09:28
0

Remove the static from int a = dat_time, and use the return from the random number as the seed for the next.

int rand3(int lim, int dat_time)
{
  int a = dat_time; // could be made the seed value                                                       
  a = (a * 32719 + 3) % 32749;
  return ((a % lim) + 1);
}

int             main()
{
  int           rd;
  time_t        timee;
  int           seed;

  timee = 0;
  timee = time(timee);
  seed = timee;
  while(42)
  {
      rd = rand3(52, seed);
      printf("%d\n", rd);
      getchar();
      seed = rd;   // < Use the new random number as the seed for the next one
  }
}
Neil
  • 11,059
  • 3
  • 31
  • 56
0

If you pass a seed along to the random number generator function, then you have to take care to change the seed every call, or you will always get the same number.

Instead I suggest you reuse the pattern used by the standard srand and rand functions, in creating two functions: One that sets the seed, and one that gets the random number. The seed will then be a global variable instead of an in-function static variable.


You can of course use a single function, but then the function has to be able to change the seed. This can be accomplished by passing the "seed"/"state" argument by reference:

int rand3(int lim, int *state)
{
    *state = (*state * 32719 + 3) % 32749;
    return ((*state % lim) + 1);
}

Then you have to use the address-of operator & when calling the function:

int rng_state = time(NULL);  /* See the initial state (aka seeding) */

for (int i = 0; i < 10; ++i)
    printf("A random number: %d\n", rand3(52, &rng_state));
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
-1

This should work, I wrote one ::

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ( void )
{
  int r;

  srand ( (unsigned)time ( NULL ) );
  r = rand();

  printf ( "random number = %d\n", r );

  return 0;
}

But I suggest, you can remove static keyword from

static int a = dat_time; // could be made the seed value
vkulkarni
  • 849
  • 1
  • 8
  • 12
  • -1 Doesn't answer the question. The OP wants help in writing his/her own random number generator. They're not asking for help with the standard library `rand()` function. – Caleb Oct 02 '13 at 13:48