A Random Number Function

I l @ ve RuBoard

A Random Number Function

Now let's look at a function that makes use of an external static variable: a random number function. The ANSI C library provides the rand() function to generate random numbers. There are a variety of algorithms for generating random numbers, and ANSI C enables implementors to choose the best algorithm for a particular machine. However, the ANSI C standard also supplies a standard, portable algorithm that produces the same random numbers on different systems. Actually, rand() is a "pseudorandom number generator," meaning that the actual sequence of numbers is predictable (computers are not known for their spontaneity), but the numbers are spread pretty uniformly over the possible range of values.

Instead of using your compiler's built-in rand() function, we'll use the portable ANSI version so that you can see what goes on inside. The scheme starts with a number called the "seed." The function uses the seed to produce a new number, which becomes the new seed. Then the new seed can be used to produce a newer seed, and so on. For this scheme to work, the random number function must remember the seed it used the last time it was called. Aha! This calls for a static variable. Listing 13.4 is version 0. (Yes, version 1 comes soon.)

Listing 13.4 The and0.c function file.
 /* rand0.c -- produces random numbers            */ /*               uses ANSI C portable algorithm  */ static unsigned long int next = 1;  /* the seed  */ int rand0(void) { /* magic formula to generate pseudorandom number */      next = next * 1103515245 + 12345;      return (unsigned int) (next/65536) % 32768; } 

In Listing 13.4 the static variable next starts with the value 1 and is altered by the magic formula each time the function is called. The result is a return value somewhere in the range of to 32767 . Note that next is external static, rather than merely static. That's because the example will be expanded later so that next is shared between two functions in the same file.

Let's try the rand0() function with the simple driver shown in Listing 13.5.

Listing 13.5 The r_drive1.c driver.
 /* r_drive1.c -- test the rand0() function */ /* compile with rand0.c                    */ #include <stdio.h> extern int rand0(void); int main(void) {     int count;     for (count = 0; count < 5; count++)         printf("%hd\n", rand0());     return 0; } 

Here's a good chance to practice using multiple files. Use one file for Listing 13.4 and one for Listing 13.5. (See Chapter 9, "Functions," or your compiler manual for guidance.) The extern keyword reminds you that rand0() is defined in a separate file.

The output is this:

 16838 5758 10113 17515 31051 

The output looks random, but let's run it again. This time the result is as follows :

 16838 5758 10113 17515 31051 

Hmmm, that looks familiar; this is the "pseudo" aspect. Each time the main program is run, you start with the same seed of 1. You can get around this problem by introducing a second function srand1() that enables you to reset the seed. The trick is to make next an external static variable known only to rand1() and srand1() . (The C library equivalent to srand1() is called srand () .) Keep rand1() and srand1() in their own file and compile that file separately. Listing 13.6 is the modification.

Listing 13.6 The s_and_r.c program.
 /* s_and_r.c -- file for rand1() and srand1()    */ /*                uses ANSI C portable algorithm */ static unsigned long int next = 1;  /* the seed  */ int rand1(void) { /* magic formula to generate pseudorandom number */     next = next * 1103515245 + 12345;     return (unsigned int) (next/65536) % 32768; } void srand1(unsigned int seed) {     next = seed; } 

Notice thawt next is an external static variable. That means it can be used by both rand1() and srand1() , but not by functions in other files. To test these functions, use the driver in Listing 13.7.

Listing 13.7 The r_drive2.c program.
 /* r_drive2.c -- test rand1() and srand1() */ /* compile with s_and_r.c                  */ #include <stdio.hw> extern void srand1(unsigned int x); extern int rand1(void); int main(void) {     int count;     unsigned seed;     printf("Please enter your choice for seed.\n");     scanf("%u", &seed);     srand1(seed);    /* reset seed */     for (count = 0; count < 5; count++)         printf("%hd\n", rand1());     return 0; } 

Again, use two files. Run the program once.

 Please enter your choice for seed. 1 16838 5758 10113 17515 31051 

Using a value of 1 for seed yields the same values as before. Now let's try a value of 3 :

 Please enter your choice for seed. 3 17747 7107 10365 8312 20622 

Very good! You get a different set of numbers.

Automated Reseeding

If your C implementation gives you access to some changing quantity, such as the system clock, you can use that value (possibly truncated) to initialize the seed value. For instance, ANSI C has a time() function that returns the system time. The time units are system dependent, but what matters here is that the return value is an arithmetic type and that its value changes with time. The exact type is system dependent and is given the label time_t , but you can use a type cast. Here's the basic setup:

 #include <time.h>   /* ANSI prototype for clock() */         srand1((unsigned int) time(0));   /* initialize seed */ 

In general, time() takes an argument that is the address of a type time_ t object. In that case, the time value is also stored at that address. However, you can pass the null pointer ( ) as an argument, in which case the value is supplied only through the return value mechanism.

You can use the same technique with the standard ANSI C functions srand() and rand() . If you do use these functions, include the stdlib.h header file. In fact, now that you've seen how srand1() and rand1() use an external static variable, you might as well use the versions your compiler supplies. We'll do that for the next example.

I l @ ve RuBoard


C++ Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 314
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net