
# flipErrs.py

import random
import matplotlib.pyplot as plt


def flip(numFlips):
  heads = 0
  for i in range(numFlips):
    if random.choice(('H', 'T')) == 'H':
      heads += 1
  return heads/numFlips


def variance(xs):
  mean = sum(xs)/len(xs)
  tot = 0.0
  for x in xs:
    tot += (x - mean)**2
  return tot/len(xs)
  

def stdDev(xs):
  return variance(xs)**0.5


def flipTrials(numFlipsInTrial, numTrials):
  fracHeads = []
  for i in range(numTrials):
    fracHeads.append( flip(numFlipsInTrial))
  mean = sum(fracHeads)/len(fracHeads)
  sd = stdDev(fracHeads)
  return (fracHeads, mean, sd)


def flipWithErrBars(min_exp, max_exp, numTrials):
  # Plots mean fraction of heads with error bars
  means, sds, xs = [], [], []
  for exp in range(min_exp, max_exp+1):
    xs.append(2**exp)
    fracHeads, mean, sd = flipTrials(2**exp, numTrials)
    means.append(mean)
    sds.append(1.96*sd)  # 95% confidence
  plt.errorbar(xs, means, yerr=sds)
  plt.semilogx()
  plt.title('Mean Fraction of Heads ('
                       + str(numTrials) + ' trials)')
  plt.xlabel('No. of flips per trial')
  plt.ylabel('Fraction of heads & 95% confidence')
  plt.show()


flipWithErrBars(3, 10, 100)
