Recipe18.11.Formatting Integers as Binary Strings


Recipe 18.11. Formatting Integers as Binary Strings

Credit: Antti Kaihola, Scott David Daniels, W.J. van der Laan

Problem

You need to display non-negative integers in binary formthat is, you need to turn them into strings made up of the characters '0' and '1'.

Solution

The best approach, assuming you must perform this task on several numbers in the course of one run of your application, is to first prepare an auxiliary table, for example, with an auxiliary function:

def _bytes_to_bits( ):     # prepare and return a list of the first 256 int as binary strings     # start with table of the right length, filled with place-holders     the_table = 256*[None]     # we'll repeatedly need to loop on [7, 6, ..., 1, 0], make it once     bits_per_byte = range(7, -1, -1)     for n in xrange(256):         # prepare the nth string: start with a list of 8 place-holders         bits = 8*[None]         for i in bits_per_byte:             # get the i-th bit as a string, shift n right for next bit             bits[i] = '01'[n&1]             n >>= 1         # join up the 8-character string of 0's and 1's into the table         the_table[n] = ''.join(bits)     return the_table # rebind function's name to the table, function not needed any more _bytes_to_bits = _bytes_to_bits( )

and then use the auxiliary table to make a fast conversion function that works 8 bits at a time:

def binary(n):     # check precondition: only non-negative numbers supported     assert n>=0     # prepare the list of substrings 8 bits at a time     bits = [  ]     while n:         bits.append(_bytes_to_bit[n&255])         n >>= 8     # we need it left-to-right, thus the reverse     bits.reverse( )     # strip leading '0's, but ensure at least one is left!     return ''.join(bits).lstrip('0') or '0'

If you need to perform this task only a very small number of times in the course of one run of your application, you might instead choose to perform the conversion directly, bit by bitit's easy, although somewhat slow. Just use the same approach as binary, but 1 bit at a time instead of 8 bits at a time:

def binary_slow(n):     assert n>=0     bits = [  ]     while n:         bits.append('01'[n&1])         n >>= 1     bits.reverse( )     return ''.join(bits) or '0'

Discussion

If you also need to display negative numbers, you can take two different roads. Either do as the built-in functions hex and oct and prepend a minus sign to negative numbers:

def bin_with_sign(n):     if n<0: return '-'+binary(-n)     else: return binary(n)

or use two's complement notation, but in that case you need to know how many bits fit in a "word", because that's how two's complement is definedin terms of fixed-length words:

def bin_twos_complement(n, bits_per_word=16):     if n<0: n = (2<<bits_per_word) + n     return binary(n)

Function binary produces just as many binary digits as each argument needs, avoiding leading '0's (except the single zero digit needed to avoid displaying an empty string when n is 0). If instead you need to produce a fixed number of binary digits, you could ensure that at string level, which is particularly easy with Python 2.4:

def bin_fixed(n, bits_per_word=16):     return bin_twos_complement(n, bits_per_word).rjust(bits_per_word, '0')

but is also quite feasible with Python 2.3 as well:

def bin_fixed_23(n, bits_per_word=16):     result = bin_twos_complement(n, bits_per_word)     return (('0'*bits_per_word)+result)[-bits_per_word:]

Alternatively, you could generalize some version of the auxiliary _bytes_to_bits function used in the "Solution", which is indeed oriented to producing fixed-length results. However, using the variable-length version, and a little string manipulation on top of it for the occasional need for fixed-length results, should be enough.

See Also

Library Reference and Python in a Nutshell docs for built-ins oct and hex; Recipe 18.12 for displaying integers in an arbitrary base.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net