tags:

views:

567

answers:

2

I used to generate random string in the following way (now I've switched to this method).

key = '%016x' % random.getrandbits(128)

The key generated this way is most often a 32 character string, but once I've got 31 chars.

This is what I don't get: why it's 32 chars, not 16? Doesn't one hex digit take one character to print?

So if I ask for %016x - shouldn't one expect sixteen chars with possible leading zeroes?

Why string legth is not always the same?

Test case

import random
import collections
stats = collections.defaultdict(int)
for i in range(1000000):
    key = '%016x' % random.getrandbits(128)
    length = len(key)
    stats[length] += 1

for key in stats:
    print key, ' ', stats[key]

Prints:

32   937911
27   1
28   9
29   221
30   3735
31   58123
+5  A: 

Yes, but the format you're using doesn't truncate -- you generate 128 random bits, which require (usually) 32 hex digits to show, and the %016 means AT LEAST 16 hex digits, but doesn't just throw away the extra ones you need to show all of that 128-bit number. Why not generate just 64 random bits if that's what you actually need? Less work for the random generator AND no formatting problems.

To satisfy your side curiosity, the length is occasionally 31 digits because 1 time in 16 the top 4 bits will all be 0; actually 1 time in 256 all the top 8 bits will be 0 so you'll get only 30 digits, etc. You've only asked for 16 digits, so the formatting will give the least number that's >= 16 and doesn't require the truncation you have not asked for.

Alex Martelli
+2  A: 

Each hex characters from 0 to F contains 4 bits of information, or half a byte. 128 bits is 16 bytes, and since it takes two hex characters to print a byte you get 32 characters. Your format string should thus be '%032x' which will always generate a 32-character string, never shorter.

jkugelman$ cat rand.py
#!/usr/bin/env python

import random
import collections
stats = collections.defaultdict(int)
for i in range(1000000):
    key = '%032x' % random.getrandbits(128)
    length = len(key)
    stats[length] += 1

for key in stats:
    print key, ' ', stats[key]
jkugelman$ python rand.py
32   1000000
John Kugelman