More efficient simluation of 2 dice rolls - Python -
i wrote program records how many times 2 fair dice need rolled match probabilities each result should expect.
i think works i'm wondering if there's more resource friendly way solve problem.
import random expected = [0.0, 0.0, 0.028, 0.056, 0.083, 0.111, 0.139, 0.167, 0.139, 0.111, 0.083, 0.056, 0.028] results = [0.0] * 13 # store our empirical results here emp_percent = [0.0] * 13 # results / count count = 0.0 # how many times have rolled dice? while true: r = random.randrange(1,7) + random.randrange(1,7) # roll our die count += 1 results[r] += 1 emp_percent = results[:] in range(len(emp_percent)): emp_percent[i] /= count emp_percent[i] = round(emp_percent[i], 3) if emp_percent == expected: break print(count) print(emp_percent)
there several problems here.
firstly, there no guarantee ever terminate, nor particularly terminate in reasonable amount of time. ignoring floating point arithmetic issues, should terminate when numbers distributed exactly right. law of large numbers not guarantee ever happen. law of large numbers works this:
- your initial results (by random chance) biased 1 way or another.
- eventually, trials not yet performed outnumber initial trials, , lack of bias in later trials outweigh initial bias.
notice initial bias never counterbalanced. rather, dwarfed rest of results. means bias tends zero, not guarantee bias vanishes in finite number of trials. indeed, predicts progressively smaller amounts of bias continue exist indefinitely. entirely possible algorithm never terminates, because there's tiny bit of bias still hanging around, statistically insignificant, still there.
that's bad enough, you're working floating point, has own issues; in particular, floating point arithmetic violates lots of conventional rules of math because computer keeps doing intermediate rounding ensure numbers continue fit memory, if repeating (in base 2) or irrational. fact rounding empirical percents 3 decimal places doesn't fix this, because not terminating decimals (base 10) terminating binary values (base 2), may still find mismatches between empirical , expected values. instead of doing this:
if emp_percent == expected: break ...you might try (in python 3.5+ only):
if all(map(math.is_close, emp_percent, expected)): break this solves both problems @ once. default, math.is_close() requires values within (about) 9 decimal places of 1 another, inserts necessary give algorithm have chance of working. note require special handling comparisons involving zero, may need tweak code use case, this:
is_close = functools.partial(math.is_close, abs_tol=1e-9) if all(map(is_close, emp_percent, expected)): break math.is_close() removes need round empiricals, since can approximation you:
is_close = functools.partial(math.is_close, rel_tol=1e-3, abs_tol=1e-5) if all(map(is_close, emp_percent, expected)): break if don't want these approximations, have give floating point , work fractions exclusively. produce exact results when divided 1 another. however, still have problem algorithm unlikely terminate (or perhaps @ all), reasons discussed above.
Comments
Post a Comment