Case Study: Random-Number Generation

Một phần của tài liệu Visual C 2012 How to Program _ www.bit.ly/taiho123 (Trang 286 - 291)

2. When the app executes, another compiler (known as the just-in-time compiler

7.9 Case Study: Random-Number Generation

Locating Additional Information About a .NET Class’s Methods

You can locate additional information about a .NET class’s methods in the.NET Framework Class Libraryreference (msdn.microsoft.com/en-us/library/ms229335.aspx). When you visit this site, you’ll see an alphabetical listing of all the namespaces in the Framework Class Library. Locate the namespace and click its link to see an alphabetical listing of all its classes, with a brief description of each. Click a class’s link to see a more complete description of the class. Click theMethodslink in the left-hand column to see a listing of the class’s methods.

7.9 Case Study: Random-Number Generation

In this and the next section, we develop a nicely structured game-playing app with multi- ple methods. The app uses most of the control statements presented thus far in the book and introduces several new programming concepts.

There’s something in the air of a casino that invigorates people—from the high rollers at the plush mahogany-and-felt craps tables to the quarter poppers at the one-armed ban- dits. It’s theelement of chance, the possibility that luck will convert a pocketful of money into a mountain of wealth. The element of chance can be introduced in an app via an object of classRandom(of namespaceSystem). Objects of classRandomcan produce random

byte,intanddoublevalues. In the next several examples, we use objects of classRandom to produce random numbers.

Creating a Random Number Generator Object

A new random-number generator object can be created as follows:

The random-number generator object can then be used to generate randombyte,intand

doublevalues—we discuss only randomintvalues here.

Generating a Random Integer Consider the following statement:

Method Next of class Random generates a random int value in the range 0 to +2,147,483,646, inclusive. If theNextmethod truly produces values at random, then every value in that range should have an equal chance (or probability) of being chosen each time methodNextis called. The values returned byNextare actuallypseudorandom numbers

a sequence of values produced by a complex mathematical calculation. The calculation uses the current time of day (which, of course, changes constantly) toseedthe random-number generator such that each execution of an app yields a different sequence of random values.

Scaling the Range of Random Numbers Produced

The range of values produced directly by methodNextoften differs from the range of val- ues required in a particular C# app. For example, an app that simulates coin tossing might

Good Programming Practice 7.1

The online .NET Framework documentation is easy to search and provides many details about each class. As you learn each class in this book, you should review the class in the online documentation for additional information.

Random randomNumbers = new Random();

int randomValue = randomNumbers.Next();

require only 0 for “heads” and 1 for “tails.” An app that simulates the rolling of a six-sided die might require random integers in the range 1–6. A video game that randomly predicts the next type of spaceship (out of four possibilities) that will fly across the horizon might require random integers in the range 1–4. For cases like these, classRandomprovides other versions of methodNext. One receives anintargument and returns a value from 0 up to, but not including, the argument’s value. For example, you might use the statement

which returns 0, 1, 2, 3, 4 or 5. The argument6—called thescaling factor—represents the number of unique values thatNextshould produce (in this case, six—0, 1, 2, 3, 4 and 5).

This manipulation is calledscalingthe range of values produced byRandommethodNext. Shifting the Range of Random Numbers Produced

Suppose we wanted to simulate a six-sided die that has the numbers 1–6 on its faces, not 0–5. Scaling the range of values alone is not enough. So weshiftthe range of numbers pro- duced. We could do this by adding ashifting value—in this case 1—to the result of meth- odNext, as in

The shifting value (1) specifies the first value in the desired set of random integers. The preceding statement assigns tofacea random integer in the range 1–6.

Combining Shifting and Scaling

The third alternative of methodNextprovides a more intuitive way to express both shift- ing and scaling. This method receives twointarguments and returns a value from the first argument’s value up to, but not including, the second argument’s value. We could use this method to write a statement equivalent to our previous statement, as in

Rolling a Six-Sided Die

To demonstrate random numbers, let’s develop an app that simulates 20 rolls of a six-sided die and displays each roll’s value. Figure 7.6 shows two sample outputs, which confirm that the results of the preceding calculation are integers in the range 1–6 and that each run of the app can produce adifferentsequence of random numbers. Theusingdirective (line 3) enables us to use classRandomwithout fully qualifying its name. Line 9 creates theRan- domobjectrandomNumbersto produce random values. Line 16 executes 20 times in a loop to roll the die. Theifstatement (lines 21–22) starts a new line of output after every five numbers, so the results will be presented on multiple lines.

int randomValue = randomNumbers.Next( 6 );

face = 1 + randomNumbers.Next( 6 );

face = randomNumbers.Next( 1, 7 );

1 // Fig. 7.6: RandomIntegers.cs

2 // Shifted and scaled random integers.

3 using System;

4

5 public class RandomIntegers 6 {

Fig. 7.6 | Shifted and scaled random integers. (Part 1 of 2.)

7.9 Case Study: Random-Number Generation 247

Rolling a Six-Sided Die 6,000,000 Times

To show that the numbers produced byNextoccur with approximately equal likelihood, let’s simulate 6,000,000 rolls of a die (Fig. 7.7). Each integer from 1 to 6 should appear approximately 1,000,000 times.

7 public static void Main( string[] args )

8 {

9

10 int face; // stores each random integer generated 11

12 // loop 20 times

13 for ( int counter = 1; counter <= 20; counter++ )

14 {

15 16 17

18 Console.Write( "{0} ", face ); // display generated value 19

20 // if counter is divisible by 5, start a new line of output 21 if ( counter % 5 == 0 )

22 Console.WriteLine();

23 } // end for 24 } // end Main

25 } // end class RandomIntegers

3 3 3 1 1 2 1 2 4 2 2 3 6 2 5 3 4 6 6 1

6 2 5 1 3 5 2 1 6 5 4 1 6 1 3 3 1 4 3 4

1 // Fig. 7.7: RollDie.cs

2 // Roll a six-sided die 6,000,000 times.

3 using System;

4

5 public class RollDie 6 {

7 public static void Main( string[] args )

8 {

9 Random randomNumbers = new Random(); // random-number generator 10

11 int frequency1 = 0; // count of 1s rolled 12 int frequency2 = 0; // count of 2s rolled

Fig. 7.7 | Roll a six-sided die 6,000,000 times. (Part 1 of 3.) Fig. 7.6 | Shifted and scaled random integers. (Part 2 of 2.)

Random randomNumbers = new Random(); // random-number generator

// pick random integer from 1 to 6 face = randomNumbers.Next( 1, 7 );

13 int frequency3 = 0; // count of 3s rolled 14 int frequency4 = 0; // count of 4s rolled 15 int frequency5 = 0; // count of 5s rolled 16 int frequency6 = 0; // count of 6s rolled 17

18 int face; // stores most recently rolled value 19

20 // summarize results of 6,000,000 rolls of a die 21 for ( int roll = 1; roll <= 6000000; ++roll )

22 {

23 24

25 // determine roll value 1-6 and increment appropriate counter

26 switch ( )

27 {

28 case 1:

29 ++frequency1; // increment the 1s counter

30 break;

31 case 2:

32 ++frequency2; // increment the 2s counter

33 break;

34 case 3:

35 ++frequency3; // increment the 3s counter

36 break;

37 case 4:

38 ++frequency4; // increment the 4s counter

39 break;

40 case 5:

41 ++frequency5; // increment the 5s counter

42 break;

43 case 6:

44 ++frequency6; // increment the 6s counter

45 break;

46 } // end switch

47 } // end for 48

49 Console.WriteLine( "Face\tFrequency" ); // output headers 50 Console.WriteLine(

51 "1\t{0}\n2\t{1}\n3\t{2}\n4\t{3}\n5\t{4}\n6\t{5}", frequency1, 52 frequency2, frequency3, frequency4, frequency5, frequency6 );

53 } // end Main 54 } // end class RollDie

Face Frequency

1 999147

2 1001249

3 999929

4 1000301

5 1000294

6 999080

Fig. 7.7 | Roll a six-sided die 6,000,000 times. (Part 2 of 3.)

face = randomNumbers.Next( 1, 7 ); // number from 1 to 6

face

7.9 Case Study: Random-Number Generation 249

As the two sample outputs show, the values produced by methodNextenable the app to realistically simulate rolling a six-sided die. The app uses nested control statements (the

switchis nested inside thefor) to determine the number of times each side of the die occurred. Theforstatement (lines 21–47) iterates 6,000,000 times. During each itera- tion, line 23 produces a random value from 1 to 6. Thisfacevalue is then used as the

switchexpression (line 26) in the switch statement (lines 26–46). Based on theface value, theswitchstatement increments one of the six counter variables during each itera- tion of the loop. (In Section 8.4, we show an elegant way to replace the entireswitchstate- ment in this app with a single statement.) Theswitchstatement has nodefault label because we have acaselabel for every possible die value that the expression in line 23 can produce. Run the app several times and observe the results. You’ll see that every time you execute this app, it produces different results.

7.9.1 Scaling and Shifting Random Numbers Previously, we demonstrated the statement

which simulates the rolling of a six-sided die. This statement always assigns to variable

facean integer in the range1 ≤face < 7. The width of this range (i.e., the number of consecutive integers in the range) is6, and the starting number in the range is1. Referring to the preceding statement, we see that the width of the range is determined by the differ- ence between the two integers passed toRandommethodNext, and the starting number of the range is the value of the first argument. We can generalize this result as

whereshiftingValuespecifies the first number in the desired range of consecutive integers andscalingFactorspecifies how many numbers are in the range.

It’s also possible to choose integers at random from sets of valuesotherthan ranges of consecutive integers. For this purpose, it’s simpler to use the version of theNextmethod that takes onlyoneargument. For example, to obtain a random value from the sequence 2, 5, 8, 11 and 14, you could use the statement

In this case,randomNumberGenerator.Next(5) produces values in the range 0–4. Each value produced is multiplied by 3 to produce a number in the sequence 0, 3, 6, 9 and 12.

Face Frequency

1 1000538

2 1002700

3 1000294

4 997662

5 999507

6 999299

face = randomNumbers.Next( 1, 7 );

number = randomNumbers.Next( shiftingValue, shiftingValue + scalingFactor );

number = 2 + 3 * randomNumbers.Next( 5 );

Fig. 7.7 | Roll a six-sided die 6,000,000 times. (Part 3 of 3.)

We then add 2 to that value toshiftthe range of values and obtain a value from the se- quence 2, 5, 8, 11 and 14. We can generalize this result as

whereshiftingValue specifies the first number in the desired range of values, difference- BetweenValuesrepresents the difference between consecutive numbers in the sequence and scalingFactorspecifies how many numbers are in the range.

7.9.2 Random-Number Repeatability for Testing and Debugging

As we mentioned earlier in this section, the methods of class Random actually generate pseudorandom numbers based on complex mathematical calculations. Repeatedly calling any ofRandom’s methods produces a sequence of numbers that appears to be random. The calculation that produces the pseudorandom numbers uses the time of day as aseed value to change the sequence’s starting point. Each newRandomobject seeds itself with a value based on the computer system’s clock at the time the object is created, enabling each exe- cution of an app to produce adifferentsequence of random numbers.

When debugging an app, it’s sometimes useful to repeat thesamesequence of pseu- dorandom numbers during each execution of the app. This repeatability enables you to prove that your app is working for a specific sequence of random numbers before you test the app with different sequences of random numbers. When repeatability is important, you can create aRandomobject as follows:

TheseedValueargument (type int) seeds the random-number calculation. If thesame

seedValueis used every time, theRandomobject produces thesamesequence of random numbers.

Một phần của tài liệu Visual C 2012 How to Program _ www.bit.ly/taiho123 (Trang 286 - 291)

Tải bản đầy đủ (PDF)

(1.020 trang)