Download 09 Something Different

Document related concepts

Large numbers wikipedia , lookup

Addition wikipedia , lookup

Collatz conjecture wikipedia , lookup

Elementary mathematics wikipedia , lookup

Law of large numbers wikipedia , lookup

Transcript
Slides for Chapter 9
Note to Instructors
This Keynote document contains the slides for “Now for Something Completely Different”, Chapter 9
of Explorations in Computing: An Introduction to Computer Science.
The book invites students to explore ideas in computer science through interactive tutorials where
they type expressions in Ruby and immediately see the results, either in a terminal window or a 2D
graphics window.
Instructors are strongly encouraged to have a Ruby session running concurrently with Keynote
in order to give live demonstrations of the Ruby code shown on the slides.
License
The slides in this Keynote document are based on copyrighted material from Explorations in
Computing: An Introduction to Computer Science, by John S. Conery.
These slides are provided free of charge to instructors who are using the textbook for their courses.
Instructors may alter the slides for use in their own courses, including but not limited to: adding new
slides, altering the wording or images found on these slides, or deleting slides.
Instructors may distribute printed copies of the slides, either in hard copy or as electronic copies in
PDF form, provided the copyright notice below is reproduced on the first slide.
© 2012 John S. Conery
Now for Something Completely Different
An algorithm for generating random numbers
✦
Pseudorandom Numbers
✦
Numbers on Demand
✦
Games with Random
Numbers
✦
Random Shuffles
✦
Tests of Randomness
Explorations in Computing
© 2012 John S. Conery
Random
✦
What does it mean for something to be “random” ?
✦
Suppose you roll a 6-sided die 10 times and record these results:
1, 2, 6, 4, 6, 3, 2, 6, 6, 1
❖is
✦
this a random sequence?
What about
1, 2, 6, 6, 6, 4, 6, 6, 6, 2
✦
Or
1, 6, 6, 6, 6, 6, 2, 6, 6, 6
commons.wikimedia.org
Random
✦
A sequence that has a lot of 6’s might be suspicious
✦
But if each number comes from an independent role the sequence is still
random
❖
✦
Probability is a related, but different, concept
❖
✦
it might not be “fair”, but it is “random”
if we know a die is “loaded” a sequence where
half the numbers are 6 would be more likely
Even if you could roll a fair die 1,000,000 times,
expect a sequence of five 6’s in a row
to appear 128 times
..., 1, 6, 6, 6, 6, 6, 2, ...
commons.wikimedia.org
Patterns
✦
Can you see a pattern in this list of numbers?
7, 2, 9, 4, 11, 6
✦
What about:
7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5, 0
7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5, 0, 7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5, 0
7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5, 0, 7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5, 0, 7, 2, 9, 4, 11, 6, 1, 8, 3, 10,
5, 0, 7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5, 0, 7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5, 0, ...
7 is always followed by 2
2 is always followed by 9...
The Rule
✦
The sequence shown on the previous slide is defined by a rule
❖
can you figure out what the rule is?
❖
i.e. given the first six numbers in the sequence can you figure out what the next one will
be?
7, 2, 9, 4, 11, 6
✦
Here’s a hint: the numbers are
all from the face of a clock
well, a clock that has
a 0 instead of a 12...
The Algorithm
✦
✦
The sequence was generated by this algorithm:
❖
each number is an hour from a 12-hour clock
❖
the first time is 7
❖
to add a new time to the sequence, add 9 hours to the most recent time
The list with 24 values:
7, 2, 9, 4, 11, 6, 1, 8,
3, 10, 5, 0, 7, 2, 9, 4,
11, 6, 1, 8, 3, 10, 5, 0
Random
✦
Before you knew what the rule was, the numbers in the list probably looked
“random”
7, 2, 9, 4, 11, 6, 1, 8, 3, 10, ...
✦
But after you know the rule they’re not
random at all -- they are predictable
✦
A definition of randomness:
❖a
sequence of numbers is random
if each number is independent of
the others
✦
Synonyms: unpredictable, uncorrelated, ...
Another Sequence
✦
Do you see a pattern here?
...8979323846264338327950288419716939937510...
✦
Here’s where those digits came from:
3.14159265358979323846264338327950288419716939937510...
Are the digits in π random?
If π is a “normal” number each digit will appear 1/10 time over any
stretch of digits
See http://pi.nersc.gov
Generating Random Numbers
✦
Our goal for this chapter: explore an algorithm that creates random values
✦
Motivation:
❖
board games
❖
card games
❖
modeling and simulation
(e.g. traffic)
❖
scientific computing
❖
other applications that
use “random samples”
http://www.bkgm.com/motif.html
A Paradox
✦
Shouldn’t an algorithm, by its very nature, be predictable?
Paradox (cont’d)
✦
The Ruby methods that implement algorithms should be predictable
>> a = sieve(100)
=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97]
>> search(a, 59)
=> 16
✦
We would not be happy if sieve left out some primes, or included some
composite numbers
❖the
whole point of calling sieve(100) is to reliably and accurately generate a list of all
primes between 2 and 100...
Exceptions to the Rule?
✦
In projects earlier we’ve used methods that don’t return the same result
each time they’re called
>> rand(100)
=> 37
>> rand(100)
=> 89
same parameters,
different results
>> rand(100)
=> 20
>> TestArray.new(5, :colors)
=> ["blue", "yellow green", "wheat", "khaki", "green"]
>> TestArray.new(5, :colors)
=> ["yellow", "black", "navy", "coral", "honeydew"]
Pseudorandom Numbers
✦
Ruby’s rand method and the RubyLabs TestArray objects do use
algorithms
❖
✦
based on rules similar to the “every 7 hours” rule shown earlier
A sequence of numbers defined by a rule will appear to be random if
❖
the sequence is very long
❖
we look at just a short segment of the sequence
❖
the rule is complex enough so there is no discernible pattern
✦
Numbers in the sequence will be “random enough” for games and other
applications
✦
The algorithm is called a pseudorandom number generator (PRNG)
PRNG in IRB
✦
✦
In-class exercise:
❖
use IRB to create a list of numbers using the “every 7 hours” rule
❖
make a new file named prng.rb
❖
type in the outline of a method named prng
❖
copy the expression from IRB to the body of the method
Later we’ll modify the method so it makes a
more realistic pseudorandom sequence...
Parameters
✦
The rule that added new items to the PRNG is
✦
A more general form uses three parameters named a, c, and m:
✦
For the “add 7 hours” rule:
❖
a=1
❖
c=7
❖
m = 12
Add Parameters to prng
✦
In-class exercise:
❖
modify the method so it uses parameters a, c, and m
❖
a call to prng(a, c, m) should make a list of m numbers defined according to the new
formula
❖
test by calling
prng(1,7,12)
Test prng
✦
✦
What do you think we’ll get if we call prng(1,8,12)?
❖
think of the clock analogy
❖
this would correspond to making a schedule for events that occur every 8 hours
In-class exercise: verify the guess using IRB
Period
✦
As you probably guessed, the sequence shows a definite pattern:
>> prng(1,8,12)
=> [0, 8, 4, 0, 8, 4, 0, 8, 4, 0, 8, 4]
✦
The sequence repeats the same three numbers over and over
✦
As soon as a number that is already in the list is added again the sequence
will start repeating from that point
✦
It’s easy to see why:
❖suppose
a number x is added for the second time
❖numbers
are defined by a formula, so whatever came after x the first time will come after x
again...
✦
The number of items in the repeating sub-sequence is called the period
The sequence defined by prng(1,8,12) has a period of 3
Period (cont’d)
✦
Since our formula is
it’s clear that only numbers between 0 and m-1 will be added to the list
✦
Sequences created by this formula will have a period of at most m
❖
some sequences will have a much shorter period
>> prng(1,7,12)
=> [0, 7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5]
>> prng(1,8,12)
=> [0, 8, 4, 0, 8, 4, 0, 8, 4, 0, 8, 4]
Choose Parameters Wisely
✦
Finding the right combination of a, c, and m can be tricky
❖
there are some tests to make
sure the period will be m
❖
c and m must have no
factors in common
❖
7 and 12 are relatively prime
❖
8 and 12 are not
8=2x2x2
12 = 2 x 2 x 3
✦
For more information look on the
Wikipedia page for “linear
congruential generator”
Parameters for m = 1000
✦
✦
Here are some parameters that work* for making a sequence of 1000
different numbers:
❖
a = 81
❖
c = 337
❖
m = 1000
In-class exercise: try it out
* but there are problems with this
sequence, as we’ll see later
>> r = prng(81, 337, 1000)
=> [0, 337, 634, 691, 308, 285, ... 749, 6, 823]
>> r.uniq.length
=> 1000
PRNG in Practice
✦
The “industrial strength” PRNGs in Ruby and other languages have very
long periods and have been tested extensively
✦
The most common PRNG (used in Java, C++, etc) has a period of 232
❖
✦
✦
approximately 4 x 109
The PRNG used in Ruby
is a newer algorithm
❖
the period is 219937
❖
~ 106600
But note: a long period is
not the only requirement...
Random Numbers for Games
✦
The PRNG can be adapted for a game-playing program or other
application
1. Convert numbers from 0 to m to a smaller range
❖
e.g. for backgammon make numbers from 1 to 6
2. Make numbers “on demand”
❖
it’s not practical to generate the full sequence of 4 billion numbers
3. Figure out how to start the sequence at a new position each time the game
is played
❖
players will be suspicious if the game starts out the same way each time...
Still to come:
• tests for randomness
• experiments with prng and other methods
Rolling the Dice
✦
The easiest way to get a number between 1 and 6 is to use the mod
function
>> r = prng(81, 337, 1000)
=> [0, 337, 634, 691, 308, 285, ... ]
>> r[1]
a number in the pseudorandom sequence
=> 337
>> r[1] % 6
the result of this expression is between 0 and 5
=> 1
>> (r[1] % 6) + 1
=> 2
this value is between 1 and 6
Rolling the Dice
✦
If we use the mod function to convert each number in the pseudorandom
sequence to a value between 1 and 6 we see a sequence that looks like
random rolls of a die
>> rolls
=> [1, 2, 5, 2, 3, 4, 3, 4, 5, 2, 1, 4, 3, 2, 3, ... ]
different patterns -- 2 is not
always followed by 5...
If you’re curious, here is the Ruby expression
used to make the array named rolls:
rolls = r.map { |x| (x % 6) + 1 }
Numbers on Demand
✦
If a PRNG has a long period we can’t make the entire sequence all at once
❖
✦
232 = 4 billion numbers = 16GB
Applications use methods that produce values “on demand”
>> p = PRNG.new(81,337,1000)
=> #<RandomLab::PRNG>
>> p.state
=> 0
PRNG is a class defined in
RandomLab
p is an object that makes
random numbers
>> p.advance
=> 337
>> roll = (p.advance % 6) + 1
=> 5
get the next random value from p
Starting the Sequence
✦
PRNG objects generate the same values as the prng_sequence method
❖
values are determined by parameters a, c, and m
>> p1 = PRNG.new(81,337,1000)
=> #<RandomLab::PRNG>
>> p2 = PRNG.new(81,337,1000)
two objects defined with
the same parameters
=> #<RandomLab::PRNG>
>> 10.times { a1 << p1.advance }
>> 10.times { a2 << p2.advance }
>> a1
get the first 10 values
from each object
=> [337, 634, 691, 308, 285, 422, 519, 376, 793, 570]
>> a2
=> [337, 634, 691, 308, 285, 422, 519, 376, 793, 570]
Starting the Sequence (cont’d)
✦
How can a game-playing application make a different sequence each time
it’s played?
✦
Answer: force the sequence to start with a specified value
>> p = PRNG.new(81,337,1000)
=> #<RandomLab::PRNG>
>> p.advance
=> 337
[337, 634, 691, 308, 285, 422, 519, ...]
>> p.seed(285)
=> 285
>> p.advance
=> 422
>> p.advance
=> 519
set the “seed” to 285
Starting the Sequence (cont’d)
✦
Next question: what value should we use for a seed?
✦
Applications typically use the time the program starts
>> Time.now
part of Ruby’s standard library
=> Sun Jan 31 13:22:25 -0800 2010
>> Time.now.to_i
number of seconds since Jan 1, 1970
(the “big bang” in the Unix universe)
=> 1264972950
>> p.seed(Time.now.to_i % 1000)
=> 972
>> p.advance
=> 69
>> p.advance
=> 926
a small difference in the seed value
leads to big differences in the sequence
of numbers
Test for Randomness (I)
✦
So far we’ve been using “intuition” to tell us whether a sequence of
numbers was random or not
❖
the pseudorandom sequence “looks random”
[337, 634, 691, 308, 285, 422, 519, ...]
✦
One way to test for randomness is to see how values are distributed
❖
the PRNG we’ve been using should make a uniform distribution
❖
when turned into numbers from 1 to 6, each “roll” should be equally likely
❖
with 1000 rolls, expect each number to appear about 1000/6 = 167 times
Making a Histogram
✦
Our first test: plot a histogram
❖
✦
aka “bar chart”
To create a histogram in RubyLabs:
>> view_histogram( [1,2,3,4,5,6] )
=> nil
the view_histogram
method will initialize a
new drawing on the
RubyLabs Canvas
a new histogram with 6
empty “bins”
Adding Items to a Histogram
✦
To add some data to the plot, call update_bin
❖
the parameter is the ID of the bin to update
❖
in this example, a number between 1 and 6 (see the array passed to view)
>> 40.times { x = (p.advance % 6) + 1; update_bin(x) }
=> 40
get 40 random numbers
place each number in its “bin”,
increasing the size of the
rectangle
Live Demo
Test for Randomness (II)
✦
Here is a longer piece of the sequence of “rolls” from our pseudorandom
sequence:
1,
6,
1,
2,
1,
4,
✦
2,
3,
6,
1,
4,
5,
5,
6,
5,
6,
3,
6,
2, 3,
1, 6,
2, 5,
1, 6,
2, 5,
...
4,
3,
2,
3,
6,
3,
2,
5,
6,
5,
4,
3,
2,
1,
2,
5,
2,
3,
4,
5,
2,
3,
4,
1,
2,
1,
4,
3,
2,
5,
4,
3,
4,
3,
2,
3,
6,
5,
2,
3,
2,
3,
2,
3,
2,
3,
2,
1,
4,
3,
4,
1,
4,
3,
4,
5,
2,
3,
6,
5,
2,
5,
6,
3,
2,
3,
6,
3,
2,
1,
2,
1,
4,
1,
4,
3,
4,
5,
2,
3,
6,
3,
2,
5,
6,
There is a pattern here -- can you spot it?
Hint: what numbers follow 2?
What numbers follow 3?
Answer: The numbers alternate
between even and odd....
1,
2,
3,
4,
1,
Test for Randomness (II)
✦
A type of display that will highlight this sort of pattern is known as a “dot
plot”
❖
get two successive random numbers:
>> x = rand(100)
=> 46
>> y = rand(100)
=> 76
❖
✦
y
plot a point at (x,y)
Repeat the process of getting
random numbers and drawing
points until the canvas starts
to fill in
x
If the values are uncorrelated the
points will be scattered at random
Dot Plot Example
✦
The plot for the PRNG we have been using as an example is shown here
❖
we can’t tell from the plot that
numbers alternate between
even and odd
❖
but the plot does show there
is definitely some sort of
correlation between pairs
of numbers
y
x
There’s something funny
going on here
Dot Plot in RubyLabs
✦
To make this plot in an IRB session:
>> view_dotplot(500)
create a blank 500 x 500 canvas
=> 500.0
>> 1000.times {
x = p.advance % 500;
y = p.advance % 500;
plot_point(x,y)
}
y
=> 1000
draw a point
on the canvas
x
Live Demo
Card Games
✦
✦
Our next experiment shows how a random number generator might be
used in a program that plays card games
❖
bridge: deal all 52 cards to 4 players (13 cards each)
❖
pinochle: special deck with 48 cards, 12 to each player
❖
poker: deal 5 (or 7) cards to any number of players
❖
blackjack: deal 2 cards to each player
❖
solitaire
❖
etc
For this project we will use a new type of Ruby object, known as a Card
❖
a hand is simply an array of Cards
Card Objects
✦
Cards are objects defined by a class named Card
❖
✦
Card is part of the RandomLab module
To make a new object, simply call Card.new
❖
the result is one of 52 cards from a standard deck, chosen at random
>> x = Card.new
=> A♣
>> h = []
=> []
>> 5.times { h << Card.new }
>> h
=> [10♥, 2♦, 6♣, 4♠, A♦]
Aside: Unicode and UTF-8
✦
The symbols used to display suits (♠♥♦♣) are part of a character set known
as Unicode
✦
Unicode is widely used in Windows, Linux, and OS X
✦
There are symbols for
❖
the “Roman” alphabet used in English
❖
accented characters in other Western European languages (é, ñ, ç, etc)
❖
Greek and Cyrillic letters (α, β, λ, etc)
❖
Asian alphabets
✦
Most web browsers and e-mail applications support Unicode
✦
But terminal emulators may not know how to display Unicode symbols
UTF-8
✦
To see these characters in the Terminal application in OS X, make sure
UTF-8 is selected in the preferences panel
Alternative Symbols
✦
If your terminal does not support UTF-8 codes (or you prefer a simpler
view) type this command in IRB:
$KCODE = ""
✦
After you enter that command the suits will be represented by single upper
case letters:
>> h
=> [10♥, 2♦, 6♣, 4♠, A♦]
>> $KCODE = ""
=> ""
>> h
=> [10H, 2D, 6C, 4S, AD]
See your Lab Manual
for more information
Back to Cards
✦
At first it might seem like the only thing we need to do to make a hand is to
call Card.new a specified number of times
✦
But there’s a problem: a card might appear more than once
✦
For games with a large number of cards in each hand it is very likely we’ll
find duplicate cards
>> h = []; 13.times { h << Card.new }; h.sort
=> [J♠, 10♠, 9♠, A♥, 9♥, J♦, 8♦, 6♦, 6♦, 5♦, 8♣, 4♣, 3♣]
Challenge
What is the probability of a
duplicate in a hand with 5
cards? with 13 cards?
Creating a Deck of Cards
✦
One way to solve this problem: simulate what happens in a real card game
❖
✦
make a “deck” with one copy of each card, i.e. an array of 52 card objects
To make a specific card, pass a number between 0 and 51 to Card.new
>> Card.new(0)
=> A♠
>> Card.new(1)
=> K♠
>> d = new_deck
=> [A♠, K♠, Q♠, ... 4♣, 3♣, 2♣]
>> d.length
=> 52
A method named new_deck
makes an array of 52 cards,
with each card appearing
exactly once
Shuffling the Deck
✦
At the start of each new game, we can “shuffle” the deck by rearranging the
objects
✦
RubyLabs has a method named permute! that randomly reorders an
array:
>> a = Array(0..9)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>> permute!(a)
=> [9, 2, 0, 7, 1, 3, 8, 5, 4, 6]
>> permute!(a)
=> [0, 7, 1, 4, 8, 9, 2, 6, 5, 3]
>> permute!(d)
=> [Q♦, 6♦, 3♥, K♠, 5♣, 8♠, ... ]
The convention in Ruby is to
include ! in the names of
methods that modify objects
Permutation Algorithm
✦
The algorithm for permuting an array is very simple
✦
It’s an iteration that exchanges an item with a random item to its right
On iteration i exchange a[i]
with a[j] where j is a random
location to the right of i
A Helper Method
✦
If there are n items in the array, on iteration i we need to pick a random
value between i and n-1
✦
RubyLabs includes a “helper method” that returns a random number
between two specified values
>> random(10,20)
=> 16
>> random(10,20)
=> 11
>> random(10,20)
=> 20
A call to random(x,y)
returns a value r such that
x ≤ r ≤ y
Parallel Assignment
✦
Ruby has a very useful operation that makes it very easy to exchange two
items in an array
✦
A parallel assignment is an assignment statement that does two
assignments at the same time
>> x, y = 5, 10
>> x
=> 5
>> y
=> 10
Parallel Assignment (cont’d)
✦
We can use a parallel assignment statement to swap two items in an array
✦
Example: exchange the two strings at a[2] and a[4]:
>> a = TestArray.new(7,:cars)
=> ["mazda", "lancia", "mini", "bmw", "lotus", "jeep", "honda"]
>> a[2], a[4] = a[4], a[2]
=> ["lotus", "mini"]
>> a
=> ["mazda", "lancia", "lotus", "bmw", "mini", "jeep", "honda"]
The permute! Method
✦
The helper method and parallel assignment make it very easy to implement
permute! in Ruby:
>> Source.listing("permute!")
1:
2:
def permute!(x)
for i in 0..x.length-2
3:
r = random(i, x.length-1)
4:
x[i], x[r] = x[r], x[i]
5:
end
6:
return x
7:
=> true
end
To see permute! in action attach a
probe to line 4 to print the contents of
array x at each iteration
Poker
✦
To test our new method for shuffling a deck of cards, we’ll do some
experiments based on poker hands
✦
There are lots of variations of poker:
✦
❖
5 card draw
❖
Texas hold-em
❖
7 card stud
❖
etc
For our experiments, we’ll use the
simplest variety, called straight poker
❖
shuffle the deck
❖
make a poker hand from the first 5 cards
❖
figure out what type of hand we have
For more information, see
“Poker” at wikipedia.com
Classifying Hands
✦
After cards are dealt, players determine what kind of hand they have
✦
One type of hand is a flush
❖
✦
Another type of hand is a straight
❖
✦
all five cards are in the same suit
five cards in a row
A straight flush is both a straight and a flush
❖
five cards in a row from the same suit
Classifying Hands (cont’d)
✦
Other types of hands are based on having groups of the same type of card
Pair
Three of a Kind
Two Pair
Four of a Kind
Full House
Ranking Hands
✦
✦
The different types of hands are
ranked according to their probability
The highest rank is for a
straight flush (p = .00154%)
See “poker probability” at wikipedia.com
Hand
Probability
straight flush
0.002%
four of a kind
0.024%
full house
0.144%
flush
0.197%
straight
0.392%
three of a kind
2.11%
two pair
4.75%
one pair
42.3%
high card
50.1%
Poker Test
✦
To test our methods for playing
cards, we’ll run an experiment
that deals poker hands
❖
call permute! to shuffle the deck
❖
make a poker hand from the
first 5 cards
❖
figure out what type of hand it is
(pair, three of a kind, etc)
❖
update a histogram that keeps
track of the number of times
each type of hand was dealt
If the random number generator is working properly
we should see about 51% “high card”, 42% “pair”,
5% “two pair”, etc
Dealing a Hand
✦
Start by making an array of 52 Card objects:
>> d = new_deck
=> [A♠, K♠, Q♠, ... 4♣, 3♣, 2♣]
✦
A call to permute! will shuffle the deck:
>> permute!(d)
=> [3♠, A♦, 6♥, ... 7♠, K♠, 10♣]
✦
This expression shuffles the deck and copies the first 5 cards to an array
named h:
>> h = permute!(d).first(5)
=> [6♦, Q♦, 10♦, 10♥, 5♣]
Classifying a Hand
✦
A method named poker_rank will classify a hand
❖
pass it an array of 5 card objects
❖
the return value will be a symbol that describes the hand
>> h = permute!(d).first(5)
=> [K♥, 3♥, 5♣, 5♥, 5♠]
>> poker_rank(h)
=> :three_of_a_kind
>> h = permute!(d).first(5)
=> [9♠, 5♠, Q♥, 7♣, J♣]
>> poker_rank(h)
=> :high_card
Create the Histogram
✦
A method named poker_rankings returns a list of all the types of hands,
sorted according to probability
>> poker_rankings
=> [:high_card, :pair, ... :straight_flush]
✦
To initialize the canvas, simply pass this array to view_histogram:
>> view_histogram(poker_rankings)
=> true
Running the Experiment
✦
To update the histogram, simply call poker_rank to figure out what sort of
hand is in h, and pass the result to update_histogram:
>> update_bin(poker_rank(h))
=> true
✦
This line combines the two steps of dealing a hand and updating the
histogram:
>> h = permute!(d).first(5); update_bin(poker_rank(h))
=> true
✦
To run the experiment, simply repeat that command several times:
>> 1000.times { h = permute!(d).first(5);
update_bin(poker_rank(h)) }
=> 1000
Results
✦
If you want to see the actual numbers displayed in the histogram, call a
method named get_counts
>> get_counts
=> {:straight_flush=>0, :high_card=>524, :two_pair=>41,
:three_of_a_kind=>29, :full_house=>1, :straight=>5,
:four_of_a_kind=>1, :flush=>4, :pair=>395}
Summary
✦
Many applications, from games to advanced simulations, need a source of
random values
✦
Numbers chosen by an algorithm are pseudorandom
✦
✦
❖
defined by a formula
❖
if you know the equation, you can predict the next number
❖
the algorithm is a pseudorandom number generator (PRNG)
A PRNG generates a long sequence of numbers
❖
short sub-sequences appear to be random
❖
applications can use them as if they were truly random
Use a seed (typically determined by the system clock) to choose a starting
place in the sequence
Summary
✦
✦
We used two types of visualizations to test the results from a PRNG
❖
histogram (bar chart) -- tell at a glance if values are evenly spread
❖
dot plot -- checks for correlations and hidden patterns
More formal, mathematical, tests are also possible
❖
e.g. chi-square test will assess the distribution of values in a histogram
Issues for PRNG Algorithms
✦
✦
✦
Developing a high quality PRNG algorithm is difficult
❖
number theory will help decide which combinations of a, c, and m will ensure the period is
m
❖
i.e. that the sequence doesn’t begin to repeat too soon
Making sure there are no hidden correlations is much more difficult
❖
trial and error and extensive tests are necessary
❖
researchers who need to make their own consult a book (e.g. Numerical Recipes) to learn
about combinations that have been tested
There are well-known examples of applications that trusted PRNG
algorithms that later turned out to have serious flaws