Random string of digits?

Peter Otten __peter__ at web.de
Sun Dec 25 10:21:49 EST 2011


Chris Angelico wrote:

> On Mon, Dec 26, 2011 at 12:30 AM, Roy Smith <roy at panix.com> wrote:
>> I want to create a string of 20 random digits (I'm OK with leading
>> zeros).  The best I came up with is:
>>
>> ''.join(str(random.randint(0, 9)) for i in range(20))
>>
>> Is there something better?
> 
> The simple option is:
> random.randint(0,99999999999999999999)
> or
> "%020d"%random.randint(0,99999999999999999999)
> (the latter gives you a string, padded with leading zeroes). But I'm
> assuming that you discarded that option due to lack of entropy (ie you
> can't trust randint() over that huge a range).
> 
> The way I'd do it would be in chunks. The simple option is one chunk;
> your original technique is twenty. We can go somewhere in between.
> First thing to do though: ascertain how far randint() is properly
> random. The Python 2 docs [1] say that the underlying random()
> function uses 53-bit floats, so you can probably rely on about that
> much randomness; for argument's sake, let's say it's safe for up to
> 10,000 but no further (although 53 bits give you about 15 decimal
> digits).
> 
> ''.join('%04d'%random.randint(0,9999) for i in range(5))
> 
> For your actual task, I'd be inclined to take ten digits, twice, and
> not bother with join():
> 
> '%010d%010d'%(random.randint(0,9999999999),random.randint(0,9999999999))
> 
> Looks a little ugly, but it works! And only two random number calls
> (which can be expensive).

Judging from a quick look into the code (method Random._randbelow()) I'd say 
you don't need to do that unless you override Random.random() and not 
Random.getrandbits(). Even if you roll your own random() you'll get a 
warning when you run into the limit:

>>> import random
>>> random.randrange(10**20)
27709407700486201379L
>>> class R(random.Random):
...     def random(self): return 4 # *
...
>>> R().randrange(10**20)
/usr/lib/python2.6/random.py:253: UserWarning: Underlying random() generator 
does not supply
enough bits to choose from a population range this large
  _warn("Underlying random() generator does not supply \n"
400000000000000000000L

(*) According to the literature 4 is the best random number, 9 being the 
runner-up: 
http://www.googlefight.com/index.php?lang=en_GB&word1=random+number+dilbert&word2=random+number+xkcd

A quick sanity check:

>>> from collections import Counter
>>> import random
>>> Counter(str(random.randrange(10**10000)))
Counter({'9': 1060, '6': 1039, '3': 1036, '8': 1007, '7': 997, '4': 977, 
'1': 976, '5': 976, '2': 970, '0': 962})





More information about the Python-list mailing list