How do I write a long integer as binary in Python?

18,152

Solution 1

Two possible solutions:

  1. Just pickle your long integer. This will write the integer in a special format which allows it to be read again, if this is all you want.

  2. Use the second code snippet in this answer to convert the long int to a big endian string (which can be easily changed to little endian if you prefer), and write this string to your file.

The problem is that the internal representation of bigints does not directly include the binary data you ask for.

Solution 2

I think for unsigned integers (and ignoring endianness) something like

import binascii

def binify(x):
    h = hex(x)[2:].rstrip('L')
    return binascii.unhexlify('0'*(32-len(h))+h)

>>> for i in 0, 1, 2**128-1:
...     print i, repr(binify(i))
... 
0 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
340282366920938463463374607431768211455 '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

might technically satisfy the requirements of having non-Python-specific output, not using an explicit mask, and (I assume) not using any non-standard modules. Not particularly elegant, though.

Solution 3

The PyPi bitarray module in combination with the builtin bin() function seems like a good combination for a solution that is simple and flexible.

bytes = bitarray(bin(my_long)[2:]).tobytes()

The endianness can be controlled with a few more lines of code. You'll have to evaluate the efficiency.

Solution 4

Why not use struct with the unsigned long long type twice?

import struct
some_file.write(struct.pack("QQ", var/(2**64), var%(2**64)))

That's documented here (scroll down to get the table with Q): http://docs.python.org/library/struct.html

Solution 5

This may not avoid the "mask and shift each integer" requirement. I'm not sure that avoiding mask and shift means in the context of Python long values.

The bytes are these:

def bytes( long_int ):
    bytes = []
    while long_int != 0:
        b = long_int%256
        bytes.insert( 0, b )
        long_int //= 256
    return bytes

You can then pack this list of bytes using struct.pack( '16b', bytes )

Share:
18,152
Jim Hunziker
Author by

Jim Hunziker

C/C++, Python, Machine learning

Updated on June 14, 2022

Comments

  • Jim Hunziker
    Jim Hunziker almost 2 years

    In Python, long integers have unlimited precision. I would like to write a 16 byte (128 bit) integer to a file. struct from the standard library supports only up to 8 byte integers. array has the same limitation. Is there a way to do this without masking and shifting each integer?

    Some clarification here: I'm writing to a file that's going to be read in from non-Python programs, so pickle is out. All 128 bits are used.

  • user1066101
    user1066101 over 13 years
    "invalid"? Could you be more specific so that I can fix it?
  • Sven Marnach
    Sven Marnach over 13 years
    There is some confusion with the variable names (n vs. long_int). Also, you probably should use n //= 256 or n >>= 8 or n, b = divmod(n, 256) instead of n /= 256 to prevent an (almost) infinite loop in Python 3 (or when a float is passed).
  • user1066101
    user1066101 over 13 years
    @Apalala, @Sven Marnach. Thanks.
  • mlvljr
    mlvljr almost 13 years
    That can probably look even nicer with long_int, b = divmod(long_int, 256) :)
  • Score_Under
    Score_Under almost 11 years
    This fails for negative input: hex(x) returns -0x123 for example.
  • DSM
    DSM almost 11 years
    @Score_Under: the very first sentence says "for unsigned integers".
  • Bailey Parker
    Bailey Parker almost 6 years
    Be careful! bin() produces something like 0b0101110, so you need to trim off the 0b prefix.
  • Bailey Parker
    Bailey Parker almost 6 years
    You also want tobytes() not tostring().