IntroCS Part 7
IntroCS Part 7
Program 2.2.8
Gambler simulation
% javac Gambler.java
% java Gambler 10 20 1000
50% wins
Avg # bets: 100
% java Gambler 50 250 100
19% wins
Avg # bets: 11050
a series of fair $1 bets, starting with some given initial stake. The gambler
always goes broke, eventually, but when we set other limits on the game, various questions arise. For example, suppose that the gambler decides ahead of
time that she will walk away after reaching a certain goal. What are the
chances that she will win, and how many bets might she have to make before
winning or losing the game?
Class Gambler in Program 2.2.8 is a simulation that can help answer
these questions. It does a sequence of trials, using Math.random to simulate
the sequence of bets, continuing until the gambler is broke or the goal
reached, and keeping track of the number of wins and the number of bets.
After running the experiment for the specified number of trials, it averages
and prints out the results. You might wish to run this program for various
values of the command-line arguments, not necessarily just to plan your next
trip to the casino, but to help you think about the following questions: Is the
simulation an accurate reflection of what would happen in real life? How
many trials are needed to get an accurate answer? What are the computational
limits on performing such a simulation? Simulations are widely used in applications in economics, science, and engineeering, and questions of this sort
are important in any simulation.
In the case of Program 2.2.8, we are merely verifying classical results
from probablity theory, which say the the probability of success is the ratio of
the stake to the goal and that the expected number of bets is the product of
the stake and the desired gain (the difference between the goal and the stake).
For example, if you want to go to Monte Carlo to try to turn $500 into $2500,
you have a reasonable (20%) chance of success, but you should expect to
make a million $1 bets!
Simulation and analysis go hand-in-hand, each validating the other.
In practice, the value of simulation is that it can suggest answers to questions
that might be too difficult to resolve with analysis. For example, suppose that
our gambler, recognizing that she will never have the time to make a million
bets, decides ahead of time to set an upper limit on the number of bets. How
much money can she expect to take home in that case? You can address this
question with an easy change to Program 2.2.8 (see Exercise 2.2.25), but
addressing it with analysis is likely to be beyond your reach.
61
62
Program 2.2.9
Factoring integers
This program prints the prime factorization of any positive integer in Javas
long data type. The code is simple,
but it takes some thought to convince
oneself that it is correct (see text).
% javac Factors.java
% java Factors 3757208
2 2 2 7 13 13 397
% java Factors 287994837222311
17 1739347 9739789
63
output
3757208
2 2
469651
67093
16
397
10
67093
17
397
469651
11
67093
18
397
469651
12
67093
19
397
469651
13
67093
20
397
469651
14
397
67093
15
397
output
13 13
output
397
This trace clearly exposes the basic operation of the program. To convince
ourselves that it is correct, we reason at a higher level of abstraction about
what we expect each of the loops to do. The while loop clearly prints and
removes from N all factors of ithe key to understanding the program is to
see that the following fact holds at the beginning of each iteration of the for
loop: N has no nontrivial factors less than i. Thus, if i is not prime, it will not
divide N; if i is prime, the while loop will do its job. Moreover, once we know
that N has no factors less than or equal to i, we also know that it has no factors
greater than N/i, so we need look no further when i is greater than N/i.
In a more naive implementation, we might simply have used the condition (i < N) to terminate the for loop. Even given the blinding speed of
modern computers, such a decision would have a dramatic effect on the size
of the numbers that we could factor. Exercise 2.2.27 encourages you to experiment with the program to learn the effectiveness of this simple change. On
a computer that can do billions of operations per second we could do num9
bers on the order of 10 in a few seconds; with the (i <= N/i) test we can do
18
numbers on the order of 10 in a comparable amount of time. Loops give us
the ability to solve difficult problems, but they also give us the ability to construct simple programs that run slowly, so we must always be congizant of
performance.
In modern applications such as cryptography (see Chapter 10), there
are actually situations where we wish to factor truly huge numbers (with, say,
64
except that the first test of the condition is omitted. If the condition initially
holds, then there is no difference.
For example, the following code sets x and y
y
(1,1)
such that (x, y) is randomly distributed in the
unit disk.
in
do
x
{
x = 2.0*Math.random() - 1.0;
y = 2.0*Math.random() - 1.0;
out
}
while (Math.sqrt(x*x + y*y) > 1.0);
With Math.Random, we get points that are randomly distributed in the unit squarewe just generate points until finding
one in the unit disk. We always want to generate at least one point, so a dowhile loop is called for. Since the area of the disk is ! and the area of the
square is 4, the expected number of times the loop is iterated is just 4 !
(about 1.27). There are a few other similar examples that we will point out
when we encounter them later in the book, but you do not need to worry
about do-while loops now. Most programmers rarely use them.
65
There are two different ways to leave this loop: either the break statement was
executed (because i divides N, so N is not prime) or the for loop condition
was not satisfied (so no i with i <= N/i was found that divides N, which
implies that N is prime). Note that we have to declare i outside the for loop
instead of in the initialization statement.
Continue statement. Java also provides a way to skip to the next iteration of a
loop: the continue statement. When a continue is executed within a loop
body, the flow of control immediately transfers to the next iteration of the
loop. Usually, it is easy to achieve the same effect with an if statement inside
the loop. The continue statement provides the exception to the rule that
while and for statements are equivalent.
Switch statement. The if and if-else statements allow one or two alternatives in directing the flow of control. Sometimes, a computation naturally
suggests more than two alternatives. We can use a sequence or a chain of ifelse statements in such situations, but the Java switch statement provides a
direct solution. We omit a formal description and move right to a typical
example: Rather than printing an int variable day in a program that works
with days of the weeks (such as a solution to Exercise 2.1.17) it would be preferable to use a switch statement, as follows:
switch (day)
{
case 0: System.out.println(Sunday);
case 1: System.out.println(Monday);
case 2: System.out.println(Tuesday);
case 3: System.out.println(Wednesday);
case 4: System.out.println(Thursday);
break;
break;
break;
break;
break;