Case Study: Random-Number Generation

Một phần của tài liệu java for programmeras 2nd edition (Trang 158 - 163)

6.8 Case Study: Random-Number Generation

We now take a brief diversion into a popular type of programming application—simula- tion and game playing. In this and the next section, we develop a nicely structured game- playing program with multiple methods. The program 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 a program via an object of classRandom(packagejava.util) or via thestaticmethodrandomof classMath. Objects of classRandomcan produce randomboolean,byte,float,double,int,longand Gaussian values, whereasMath method random can produce onlydouble values in the range0.0 ≤x < 1.0, wherexis the value returned by methodrandom. In the next several examples, we use objects of classRandomto produce random values.

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

It can then be used to generate randomboolean,byte,float,double, int, longand Gaussian values—we discuss only randomintvalues here. For more information on the

Randomclass, seedownload.oracle.com/javase/6/docs/api/java/util/Random.html. Consider the following statement:

Randommethod nextIntgenerates a randomintvalue in the range –2,147,483,648 to +2,147,483,647, inclusive. If it truly produces values at random, then every value in the range should have an equal chance (or probability) of being chosen each timenextIntis called. The numbers are actually pseudorandom numbers—a sequence of values pro- duced 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 a program yields a different sequence of random values.

javax.swing TheJava Swing GUI Components Packagecontains classes and inter- faces for Java’s Swing GUI components that provide support for porta- ble GUIs. (See Chapter 14, GUI Components: Part 1, and Chapter 22, GUI Components: Part 2.)

javax.swing.event TheJava Swing Event Packagecontains classes and interfaces that enable event handling (e.g., responding to button clicks) for GUI com- ponents in packagejavax.swing. (See Chapter 14, GUI Components:

Part 1, and Chapter 22, GUI Components: Part 2.)

javax.xml.ws TheJAX-WS Packagecontains classes and interfaces for working with web services in Java. (See Chapter 28, Web Services.)

Random randomNumbers = new Random();

int randomValue = randomNumbers.nextInt();

Package Description

Fig. 6.4 | Java API packages (a subset). (Part 2 of 2.)

126 Chapter 6 Methods: A Deeper Look

The range of values produced directly by methodnextIntgenerally differs from the range of values required in a particular Java application. For example, a program that sim- ulates coin tossing might require only 0 for “heads” and 1 for “tails.” A program that sim- ulates the rolling of a six-sided die might require random integers in the range 1–6. A program that randomly predicts the next type of spaceship (out of four possibilities) that will fly across the horizon in a video game might require random integers in the range 1–

4. For cases like these, class Random provides another version of methodnextInt that receives anintargument and returns a value from 0 up to, but not including, the argu- ment’s value. For example, for coin tossing, the following statement returns 0 or 1.

Rolling a Six-Sided Die

To demonstrate random numbers, let’s develop a program that simulates 20 rolls of a six- sided die and displays the value of each roll. We begin by usingnextIntto produce ran- dom values in the range 0–5, as follows:

The argument6—called thescaling factor—represents the number of unique values that

nextIntshould produce (in this case six—0, 1, 2, 3, 4 and 5). This manipulation is called scalingthe range of values produced byRandommethodnextInt.

A six-sided die has the numbers 1–6 on its faces, not 0–5. So weshiftthe range of numbers produced by adding ashifting value—in this case 1—to our previous result, as in

The shifting value (1) specifies thefirstvalue in the desired range of random integers. The preceding statement assignsfacea random integer in the range 1–6.

Figure 6.5 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 program can produce a different sequence of random numbers. Line 3 imports classRandomfrom thejava.util package. Line 9 creates theRandomobjectrandomNumbersto produce random values. Line 16 executes 20 times in a loop to roll the die. Theifstatement (lines 21–22) in the loop starts a new line of output after every five numbers.

int randomValue = randomNumbers.nextInt( 2 );

face = randomNumbers.nextInt( 6 );

face = 1 + randomNumbers.nextInt( 6 );

1 // Fig. 6.5: RandomIntegers.java 2 // Shifted and scaled random integers.

3 4

5 public class RandomIntegers 6 {

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 {

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

import java.util.Random; // program uses class Random

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

6.8 Case Study: Random-Number Generation 127

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

To show that the numbers produced bynextIntoccur with approximately equal likeli- hood, let’s simulate 6,000,000 rolls of a die with the application in Fig. 6.6. Each integer from 1 to 6 should appear approximately 1,000,000 times.

15 16 17

18 System.out.printf( "%d ", face ); // display generated value 19

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

22 System.out.println();

23 } // end for 24 } // end main

25 } // end class RandomIntegers

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

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

1 // Fig. 6.6: RollDie.java

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

3 import java.util.Random;

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; // maintains count of 1s rolled 12 int frequency2 = 0; // count of 2s rolled

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; // most recently rolled value 19

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

// pick random integer from 1 to 6 face = 1 + randomNumbers.nextInt( 6 );

128 Chapter 6 Methods: A Deeper Look

20 // tally counts for 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; // optional at end of switch

46 } // end switch

47 } // end for 48

49 System.out.println( "Face\tFrequency" ); // output headers 50 System.out.printf( "1\t%d\n2\t%d\n3\t%d\n4\t%d\n5\t%d\n6\t%d\n", 51 frequency1, frequency2, frequency3, frequency4,

52 frequency5, frequency6 );

53 } // end main 54 } // end class RollDie

Face Frequency

1 999501

2 1000412

3 998262

4 1000820

5 1002245

6 998760

Face Frequency

1 999647

2 999557

3 999571

4 1000376

5 1000701

6 1000148

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

face = 1 + randomNumbers.nextInt( 6 ); // number from 1 to 6

face

6.8 Case Study: Random-Number Generation 129

As the sample outputs show, scaling and shifting the values produced by nextInt enables the program to simulate rolling a six-sided die. The application uses nested control statements (theswitchis nested inside thefor) to determine the number of times each side of the die appears. Theforstatement (lines 21–47) iterates 6,000,000 times. During each iteration, line 23 produces a random value from 1 to 6. That value is then used as the controlling expression (line 26) of theswitchstatement (lines 26–46). Based on theface value, theswitchstatement increments one of the six counter variables during each itera- tion of the loop. When we study arrays in Chapter 7, we’ll show an elegant way to replace the entireswitchstatement in this program with a single statement! Thisswitch state- ment has nodefaultcase, because we have acasefor every possible die value that the expression in line 23 could produce. Run the program, and observe the results. As you’ll see, every time you run this program, it produces different results.

6.8.1 Generalized Scaling and Shifting of Random Numbers Previously, we simulated the rolling of a six-sided die with the statement

This statement always assigns to variablefacean integer in the range1 ≤face ≤6. The width of this range (i.e., the number of consecutive integers in the range) is6, and the start- ing number in the range is1. In the preceding statement, the width of the range is deter- mined by the number6that’s passed as an argument toRandommethodnextInt, and the starting number of the range is the number 1 that’s added to randomNumberGenera- tor.nextInt(6). 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 values other than ranges of consecutive integers. 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.nextInt(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.

We add 2 to that value to shift the range of values and obtain a value from the sequence 2, 5, 8, 11 and 14. We can generalize this result as

where shiftingValue specifies the first number in the desired range of values,difference- BetweenValuesrepresents the constant difference between consecutive numbers in the se- quence andscalingFactorspecifies how many numbers are in the range.

6.8.2 Random-Number Repeatability for Testing and Debugging

Class Random’s methods actually generate pseudorandom numbers based on complex mathematical calculations—the sequence of numbers appears to be random. The calcula- tion that produces the numbers uses the time of day as a seed valueto change the se-

face = 1 + randomNumbers.nextInt( 6 );

number = shiftingValue + randomNumbers.nextInt( scalingFactor );

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

number = shiftingValue +

differenceBetweenValues * randomNumbers.nextInt( scalingFactor );

130 Chapter 6 Methods: A Deeper Look

quence’s starting point. Each new Random object seeds itself with a value based on the computer system’s clock at the time the object is created, enabling each execution of a pro- gram to produce a different sequence of random numbers.

When debugging an application, it’s often useful to repeat the exact same sequence of pseudorandom numbers during each execution of the program. This repeatability enables you to prove that your application is working for a specific sequence of random numbers before you test it with different sequences of random numbers. When repeatability is important, you can create aRandomobject as follows:

The seedValue argument (of type long) seeds the random-number calculation. If the sameseedValueis used every time, theRandomobject produces the same sequence of num- bers. You can set aRandomobject’s seed at any time during program execution by calling the object’ssetmethod, as in

Một phần của tài liệu java for programmeras 2nd edition (Trang 158 - 163)

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

(1.164 trang)