Monte Carlo simulation of the Monty Hall Problem in Ruby and Python
antoniocangiano.com
antoniocangiano.com
def main(iter=100000):
stay_win = 0.0
switch_win = 0.0
for i in xrange(iter):
win_door = int(numpy.random.uniform()*3)
pick_door = int(numpy.random.uniform()*3)
if pick_door == win_door:
stay_win += 1.0
else:
switch_win += 1.0
print 'stay: ', stay_win/float(iter)
print 'switch: ', switch_win/float(iter)
return (defun monty-hall (strategy &aux (winner (random 3)) (choice (random 3)))
(let ((monty (if (= winner choice)
(do ((x (random 3) (random 3)))
((/= x winner) x))
(- 3 (+ winner choice)))))
(case strategy
(:stay (= winner choice))
(:change (= winner (- 3 (+ choice monty)))))))
(looping and reporting omitted)Incidentally, I think the code in the original article provides a good example of how code can be so verbose as to detract from understanding. Good code clarifies a problem rather than obfuscating it under the weight of useless detail.
1. The only leap of logic required is to realize that the two options are mutually exclusive: either you win by staying or you win by switching. There is no alternative.
2. Writing the code in that concise form, I believe the inherent structure of the problem is much clearer than the mess of classes and function calls.
That way you can do increments with integers which should be cheaper.
Random tangent: a while ago I was working on a project where we used a big fancy MCMC algorithm to do some computer vision task. One issue we ran into was that double types didn't have enough precision to compute the partition function. We spent along while trying to figure out a way around having to compute it, and put in 10-20k lines of C++ code to make it happen. Really complicated. Took forever. One day I had the rather silly idea to just use an arbitrary precision floating point library. It was a silly idea because we profiled it and found that it was 20x slower for all floating point computations which seemed to be the bulk of the algorithm (and performance REALLY mattered here.) I decided to try it out on the theory that 90% of the CPU time was spent on memory access, looping, and program jumps, and that even though we had a ton of floating point operations, they were basically free. So I implemented it, and as it turned out we did indeed get a 20x slowdown on our floating point computations. But the overall algorithm only lost about 1% or so, because the floating points stuff only constituted a tiny fraction of the total cost. Since then I just ignore the cost of arithmetic and focus 100% on optimizing program flow. Almost seems obvious in retrospect, but I still see code where people jump through hoops to save a few multiplications, even though in the end it usually costs them more due to cache misses inherent in loops and program jumps.
Did you even read the part where he said his code was intentionally simplistic and not optimized? Making a fast/efficient simulation was not the point at all.
axiom, I apologize. I don't know what got into me.