“Please do not be alarmed by anything you see or hear around you … We are now cruising at a level of two to the power of two hundred and seventy-six thousand to one against and falling, and we will be restoring normality just as soon as we are sure what is normal anyway. Thank you …”
Inside a bag are 9 coins. 4 of these coins are fair, in that they have a 50% chance of coming up heads. The other 5 coins in the bag are unfair coins. When they are flipped, they have a 65% chance of coming up heads. What are the chances, expressed as a percentage, that when drawing a random coin from the bag and flipping it 3 times, it will come up heads all 3 times?
Finding the answer is slightly tedious, but not difficult. First you have to consider what would happen if you randomly chose a fair coin from the bag, then you have to consider what would happen if you randomly chose an unfair coin. Add those two possibilities together, and there’s your answer.
Fair coin
First, let’s look at what happens when you draw a fair coin from the bag and flip it three times. The chances of one flip coming up heads are 50%. Twice would be 50% squared, and three times would be 50% cubed. You can express this as .5^3, or .125, or 12.5%. Since only 4 of the 9 coins in the bag are fair, you need to multiply .125 by 4/9. That puts the chances of pulling a fair coin and having it come up heads on all three flips at about 5.56%.
Unfair coin
The way to find the chances of pulling an unfair coin and getting three heads is the same. .65^3 = about 27.46%, and since there are 5 unfair coins from 9 total, .2746 * 5/9 = about .1526, or 15.26%.
Add them up
All that’s left now is to add the chances of the two possibilities together to get the total chances of pulling any coin from the bag and getting three heads. 5.56% + 15.26% = 20.82%. The equation should look like this:
probability = (.50 ^ 3 * 4 / 9) + (.65 ^ 3 * 5 / 9)
And when you do it that way, you end up with about 20.81% instead of 20.82%, because you’re only rounding the final answer instead of rounding the answers to intermediate steps.
The proof
So I wanted to test this out and see what Python would do when simulating such a scenario 100,000 times. Here is the code I came up with:
# coinflips.py
# a program to test the concept presented at
# http://www.khanacademy.org/math/probability/v/dependent-probability-example-1
# by Daniel Veazey <danielveazey@gmail.com>
import random
# what happens when you flip a coin a number of times, depending on
# whether the coin is fair or unfair (weighted)
# a pseudo-random number is genereated from 1 to 100
# and compared to what its odds of landing on heads are
# return True for heads if result is below odds
# or return False for tails if the result is above the odds
def flipping(how_many_flips, odds):
no_of_heads = 0
for flip in range(0, how_many_flips):
flip_result = random.randint(1, 100)
if flip_result <= odds:
no_of_heads += 1
return no_of_heads == how_many_flips
# choosing a coin pseudo-randomly
# pseudo-random integer is generated from the number of coins available
# and compared to the number of fair coins available
# True = unfair coin; False = fair coin
def choosing_coin(how_many_fair, how_many_unfair):
total_coins = how_many_fair + how_many_unfair
chosen_coin = random.randint(1, total_coins)
return chosen_coin > how_many_fair
# ask user for parameters of test
print "Testing probability of fair and unfair coin flips when a random coin is pulled from a bag.\n"
fair_coins = float(raw_input("How many fair coins do you wish to put in the bag? "))
unfair_coins = float(raw_input("How many unfair coins do you wish to put in the bag? "))
unfair_odds = float(raw_input("For the unfair coins, what percent chance does one flip have that it will come up heads? "))
number_of_flips = float(raw_input("How many times do you want to flip the coin chosen from the bag? "))
# tell the user what the probability is
print "\nThe chances of getting", int(number_of_flips), "heads in a row are about", float("%.4f" % ((((unfair_odds / 100.00) ** number_of_flips) * unfair_coins / (fair_coins + unfair_coins)) + ((.50 ** number_of_flips) * fair_coins / (fair_coins + unfair_coins))))*100.00, "percent."
print "I am now running the simulation 100,000 times. This may take a few seconds.\n"
# the simulation: success is the number of times the flips came up all heads
success = 0
for x in range(100000):
# choose a coin
if choosing_coin(fair_coins, unfair_coins) == True:
# flipping an unfair coin
if flipping(int(number_of_flips), (unfair_odds)) == True:
success += 1
# flipping a fair coin
else:
if flipping(int(number_of_flips), 50) == True:
success += 1
print "Simulation complete. All heads came up", success, "out of 100,000 times."And here is what Python told me:
Testing probability of fair and unfair coin flips when a random coin is pulled from a bag. How many fair coins do you wish to put in the bag? 4 How many unfair coins do you wish to put in the bag? 5 For the unfair coins, what percent chance does one flip have that it will come up heads? 65 How many times do you want to flip the coin chosen from the bag? 3 The chances of getting 3 heads in a row are about 20.81 percent. I am now running the simulation 100,000 times. This may take a few seconds. Simulation complete. All heads came up 20621 out of 100,000 times.
How it works
After importing the random module, the first function I defined is flipping(how_many_flips, odds). It generates a pseudo-random number and compares it to the odds that are passed to the function. If the number comes in under the odds, then it adds one to the variable no_of_heads. It does this again as many times as necessary to meet the value of how_many_flips were passed to it. Once it has done that, it returns True if no_of_heads is equal to how_many_flips. Otherwise it returns False.
The second function defined is choosing_coin(how_many_fair, how_many_unfair). Another pseudo-random number is generated, between 1 and the total number of coins that are available. If the random number is greater than how_many_fair, the function returns True to tell that an unfair coin was chosen. Otherwise it returns False.
Now Python asks for some data from the user. It wants to know how many fair_coins and unfair_coins there are, how unfair the unfair coins are (unfair_odds), and number_of_flips that the user wants it to do on the chosen coin.
All these variables are assigned as floating point variables, but there is room for improvement here. It would be better if I had made them decimals, but it seems that whenever I try to use decimals in Python, instead of getting what I’m expecting, I get stuff like this:
>>> decimal.getcontext().prec = 2
>>> decimal.Decimal(4.56)
Decimal('4.55999999999999960920149533194489777088165283203125')
>>> x = decimal.Decimal(4.56)
>>> x
Decimal('4.55999999999999960920149533194489777088165283203125')
>>> y = decimal.Decimal(2.3)
>>> y
Decimal('2.29999999999999982236431605997495353221893310546875')
>>> x + y
Decimal('6.9')
>>>
So I’m leaving it as floating point variables right now. I need to read more about decimals in Python, and once I figure out how to use them correctly, I might change those variables to decimals if I haven’t moved on to bigger and better things. Now back to the program.
After getting the values from the user, Python calculates the probability using the previously mentioned equation. Then it runs a simulation using those numbers 100,000 times. It calls the choosing_coin() function, and if it is returned True for an unfair coin, it calls the flipping() function and passes the unfair_odds to it. If choosing_coin() returns False, the program calls flipping() with 50 as the odds. When it passes number_of_flips to the flipping() function, it passes it as an integer because a for loop requires the values in the range to be integers, and it would encounter an error if it tried to use a floating point variable as one of the range’s values.
So if flipping() returns True for either using the unfair_odds or 50 for fair odds, Python keeps track of it by adding 1 to the value of the variable named success. Finally, it tells the results of its tests. It’s usually very close to its corresponding probability.





With a little help from some online forums, I learned how to handle decimals properly in Python. Here is a link to the new code:
http://pastebin.com/SKezizDG