2
\$\begingroup\$

My goal is to take any size number, and convert it to a string of smaller characters that represent the concatenation of the binary expansion of the number. To illustrate what I am talking about, here is an example using the number 4820:

4820's binary:   0001001011010100   #   16 bits of binary, enough to store the number 4820
Separated:     00010010  11010100   #   Simply split the binary into two char size pieces
Characters:      '\x12'       'Ô'   #   Converted the binary snippets into their respective characters
Together:                 '\x12Ô'   # The concatenation of the characters, this is what I need

I wrote a algorithm in Python to do the job for me, but I'm not sure if there is a easier way to do it, or if my algorithm is as efficient as it can be.

def to_chars(number, length):                             #takes number and expected binary length
    string = bin(number)[2:]                              #built-in binary conversion
    expanded = ('0' * (length - len(string))) + string    #expand the binary
    chars = ''
    for pos in range(int(length / 8)):                    #iterates over chunks of 8 bits
        section = expanded[8 * pos : 8 * (pos + 1)]       #gets the binary snippet
        chars += chr(int(section, 2))                     #converts the binary into a character
    return chars                                          #return the concatenated string

There has to be a lower level, possibly built in way to do the same thing, but faster. In a way, this is just the conversion from one data type to another, but I can't figure out a faster way.

Here are a few benchmarks:

%timeit to_chars(4820, 16)
100000 loops, best of 3: 3.04 µs per loop

%timeit to_chars(4820, 32)
100000 loops, best of 3: 4.6 µs per loop

%timeit to_chars(690655640, 32)
100000 loops, best of 3: 4.59 µs per loop
\$\endgroup\$
2
\$\begingroup\$

Well, it's not a huge performance improvement, but at least it's a lot cleaner:

def to_chars2(number, length):
    bin_num = bin(number)[2:].zfill(length)
    return ''.join([chr(int(bin_num[s:s+8], 2)) for s in range(0, len(bin_num), 8)])

Benchmarks:

>>> timeit(lambda: to_chars2(4820, 16))
1.590714931488037
>>> timeit(lambda: to_chars(4820, 16))
1.6366891860961914
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Be careful when using lambdas for timing, as the time to execute the statement also accounts for the time to access the lambda. This isnt really applicable here because the function is not too fast, but if it was faster, that would be something to note. But otherwise, nice cleanup! \$\endgroup\$ – Nick Pandolfi Jun 25 '14 at 21:42
  • \$\begingroup\$ I actually got a slower time with your version, not by much, but still slower. \$\endgroup\$ – Nick Pandolfi Jun 25 '14 at 22:28
1
\$\begingroup\$

Actually, ignore my previous answer. You're looking for the binascii module. It uses C modules for performance.

>>> timeit(lambda: binascii.unhexlify(hex(4820)[2:]))
0.379443883895874
\$\endgroup\$
4
  • \$\begingroup\$ I would delete this answer, and edit the original answer by adding this answer on , with some extra elaboration. But dont delete anything from the other answer. \$\endgroup\$ – Nick Pandolfi Jun 25 '14 at 21:46
  • \$\begingroup\$ And this also doesn't seem to give me the answer I want, but maybe I am doing something incorrect... \$\endgroup\$ – Nick Pandolfi Jun 25 '14 at 21:55
  • \$\begingroup\$ @nickpandolfi I believe the difference in answers is because you mistranslated 4820 in your example. The binary you wrote was for 4829. 4820 is 1001011010100. \$\endgroup\$ – whereswalden Jun 26 '14 at 11:50
  • \$\begingroup\$ My mistake, but the characters are still correct, I will fix that. \$\endgroup\$ – Nick Pandolfi Jun 26 '14 at 16:27
0
\$\begingroup\$

My problem was that I was just not well educated enough about the subject, but after some experimentation, I found the solution. After I tried to save the full range of unicode characters into a file, I ran into a few errors, saying that some of the characters mapped to an undefined symbol, which was out of my control. I decided to try to convert int types into bytes types then, so they can be saved to the file. The solution was extremely simple.

In [21]: x = 4820
In [22]: x.to_bytes(2, byteorder = 'big') # we want it to fit 4820 into 2 bytes, using big endian byte-order
Out[22]: b'\x12\xd4' # This is what I wanted, it just looks a little different

This functionality is exactly what I needed, and I simply overlooked the methods from python's int data type.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.