Finding the exponent of n = 2**x using bitwise operations [logarithm in base 2 of n]

后端 未结 7 1110
猫巷女王i
猫巷女王i 2020-12-31 05:47

Is there a straightforward way to extracting the exponent from a power of 2 using bitwise operations only?

EDIT: Although the question was originall

7条回答
  •  情深已故
    2020-12-31 06:22

    It seems like the range is known. Let's assume it goes up to 1<<20, just to make it more interesting:

    max_log2=20
    

    So make a list that (in effect) maps an integer to its base 2 logarithm. The following will do the trick:

    log2s_table=[0]*((1<

    (This doesn't do anything useful for numbers that aren't powers of two; the problem statement suggests they don't need to be handled. Would be easy enough to fix that though.)

    The function to get the logarithm is very simple, and could easily be inlined:

    def table(v):
        return log2s_table[v]
    

    I can't guarantee that the test code I wrote is exactly the same as the one being used to get the example timings, but this is rather quicker than the stringcount code:

    stringcount: 0.43 s.
    table: 0.16 s.
    

    Since all the values in the table are less than 256, I wondered whether using a string instead of a list would be quicker, or maybe an array.array of bytes, but no dice:

    string: 0.25 s.
    arr: 0.21 s.
    

    Using a dict to do the lookup is another possibility, taking advantage of the way only powers of two are being checked:

    log2s_map=dict([(1<

    The results for this weren't as good, though:

    map: 0.20 s.
    

    And just for fun one could also use the hex method on float objects to get a string that includes (as its last part) the base 2 exponent of the number. This is a bit slow to extract in general, but if the exponent is only ever going to be one digit it could be done straightforwardly enough:

    def floathex(v):
        return ord(float(v).hex()[-1])-48
    

    This is purely for entertainment value though as it was uncompetetive -- though, amazingly, still quicker than the bitwise approach.

    So it looks like using a list is the way to go.

    (This approach won't scale indefinitely, due to limited memory, but to make up for that the execution speed won't depend on max_log2, or the input values, in any way that you'll notice when running python code. Regarding the memory consumption, if I remember my python internals correctly, the table will take up about (1< bytes, because the contents are all small integers that the interpreter will intern automatically. SO, when max_log2 is 20, that's about 4MB.)

提交回复
热议问题