random picks from a list

Anton Vredegoor anton at vredegoor.doge.nl
Thu Jun 12 20:48:20 EDT 2003


Manuel Garcia <news at manuelmgarcia.com> wrote:

>Actually, you may not want to do this.  If you pick your numbers from
>a list of 'likely winning' numbers, or even if you try to 'juke' the
>game and pick your numbers from a list of 'unlikely winning' numbers,
>you are competing against people who are trying exactly the same
>strategy, or a similar strategy.  So if you do win, you will be more
>likely to have to share your winnings.
>
>(Not that the problem of 'sharing your lottery winnings' is a very
>common or worrisome problem... ;-)
>
>You can read more about it from The Straight Dope:
>
>http://www.straightdope.com/classics/a4_119.html
>
>Just pick your numbers completely randomly, and the chances of having
>to share lottery winnings will be made as small as possible.  Python's
>random number generator has been 'beefed-up' to the Mersenne Twister
>generator in Python 2.3 (currently in beta), so you can rest assured
>that your random numbers are just as good as anyone else's (except
>professional cryptographers, who get their random numbers from fancy
>hardware).

Well, since it's friday the thirteenth today I didn't want to do this,
but having Python programmers rely on brute force Mersenne Twisting
for choosing lottery numbers could give them a disadvantage.

For example a list of 49 items gives:

608281864034267560872252163321295376887552831379210240000000000

possible permutations, while there's only 53 bit precision floats.
The impressive period of the Mersenne Twister (2**19937-1) should not
distract from the fact that there's not enough floating point bits to
assign a unique floating point number to each of the possible
permutations of this list. In Python23 there seems to be a sample
function but I'm not completely sure that it solves this issue. Does
it call the Twister separately for each item, and if it did would it
make enough of a difference? I'll leave that question to the
mathematicians and floating point specialists.

Maybe this program gives Python programmers a better winning chance
with choosing 6 out of 49 for example, because it first chooses from a
relatively small set of combinations, and next it chooses from an even
smaller number of permutations. 

Anton

#sample.py
from operator import mul
from random import randrange

class combinations:
    
    def __init__(self,n,k):
        self.n,self.k,self.count = n,k,noverk(n,k)
    
    def __getitem__(self,index):
        #combination number index
        if index > self.count - 1: raise IndexError
        res,x,rest = [],self.n,index
        for i in range(self.k,0,-1):
            while noverk(x,i) > rest : x -= 1
            rest -= noverk(x,i)
            res.append(x)
        return res

def indexedperm(L,index):
    m,n = index,len(L)
    res,T = L[:],L[:]
    for i in range(n):
        m,d = divmod(m,n-i)
        res[i] = T.pop(d)
    return res

def fac(n):
    return reduce(mul,range(2,n+1),1L)
        
def noverk(n,k):
    #compute n over k
    return reduce(lambda a,b: a*(n-b)/(b+1),range(k),1)

def sample(population,k):
    n = len(population)
    C = combinations(n,k)
    nc,np = C.count,fac(k)
    c_idx,p_idx = randrange(nc),randrange(np)
    seq = indexedperm(C[c_idx],p_idx)
    return [population[i] for i in seq]
    
def test():
    print sample(range(1,50),6)

if __name__ == '__main__':
    test()







More information about the Python-list mailing list