Viewing file: Random.py (2.64 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Lib/Random.py,v 1.4 2005/02/09 11:24:33 mbrown Exp $ """ Thread-safe random number generation
We consider a physical source of entropy to be better than a simulated one, so we will try to use one (/dev/urandom on posix, for example). If a pseudo-random number generator is to be used, it should be seeded from the physical source, if possible, rather than the usual custom of seeding it from the system clock. Random number sources that are not known to be thread-safe should be polled serially.
Copyright 2005 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
__all__ = ['dev_rand_fd', 'pseudo_rng', 'GetRandomBytes', 'Random']
import os, sys, random, threading
pseudo_rng = random.Random() lock = threading.Lock() py22 = sys.version_info[0:2] < (2,3)
dev_rand_fd = None if os.name == 'posix': try: dev_rand_fd = os.open('/dev/urandom', os.O_RDONLY) except IOError: pass
def GetRandomBytes(numBytes): """Returns numBytes random bytes from the best RNG available""" bytes = '' if dev_rand_fd is not None: lock.acquire() while len(bytes) < numBytes: bytes += os.read(dev_rand_fd, numBytes - len(bytes)) lock.release() else: for i in xrange(numBytes): if py22: lock.acquire() byte = pseudo_rng.randrange(0, 256) if py22: lock.release() bytes += chr(byte) return bytes
# The pseudo-RNG will be seeded from the system clock, normally, # but if we have dev_rand_fd, we can seed it more randomly. In this # situation, we probably won't be using the psuedo-RNG, ourselves, # so this is just for the benefit of whatever else might end up # using it. if dev_rand_fd is not None: # the idea here is to be between 0L and 27814431486575L # which is what the Wichmann-Hill pseudo-RNG needs (Py 2.2-) pseudo_rng.seed(reduce(lambda a,b: ((a+1)*(b+1))%27814431486576L -1, map(ord,GetRandomBytes(6))))
def Random(): """Returns a random float, n, where 0 <= n < 1""" if dev_rand_fd is not None: # is there a more efficient, mathematical way to do this? s = '0.' + reduce(lambda a,b: str(a) + str(b % 10), map(lambda b: int(ord(b)/25.6), GetRandomBytes(18))) n = float(s) else: if py22: lock.acquire() n = pseudo_rng.random() if py22: lock.release() return n
|