Skip to content

Instantly share code, notes, and snippets.

@zacharyvoase
Created June 2, 2009 04:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zacharyvoase/122001 to your computer and use it in GitHub Desktop.
Save zacharyvoase/122001 to your computer and use it in GitHub Desktop.
montecarlo()
# -*- coding: utf-8 -*-
from decimal import Decimal
import random
def montecarlo(choices):
"""
It's easier for me to explain this with an example.
>>> choices = {
... 0.2: 1
... 0.3: 2
... 0.5: 3
... }
There's a 20% probability of producing 1, 30% of producing 2, and 50% of
producing 3.
>>> montecarlo(choices)
3
The probabilities don't have to add up to 1, either; they could have been
4, 6 and 10 and it would have been the same.
"""
cumulative_probabilities = {Decimal(0): None}
probability_sum = Decimal(0)
sorted_choices = sorted(choices.items(), key=lambda pair: pair[0])
for probability, outcome in sorted_choices:
if isinstance(probability, (Decimal, int, long)):
probability_sum += probability
elif isinstance(probability, float):
# This will typically round up a bit, but floating points lose
# some precision anyway.
probability_sum += Decimal(str(probability))
elif isinstance(probability, basestring):
probability_sum += Decimal(probability)
cumulative_probabilities[probability_sum] = outcome
rand_number = Decimal(str(random.random())) * probability_sum
prev = 0
sorted_probs = sorted(
cumulative_probabilities.items(), key=lambda pair: pair[0])
for cum_prob, outcome in sorted_probs:
if prev < rand_number <= cum_prob:
prev, result = cum_prob, outcome
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment