prova Ammettiamolo:
import collections
import math
import timeit
def power_bit_length(x):
return 2**(x-1).bit_length()
def shift_bit_length(x):
return 1<<(x-1).bit_length()
def power_log(x):
return 2**(math.ceil(math.log(x, 2)))
def test(f):
collections.deque((f(i) for i in range(1, 1000001)), maxlen=0)
def timetest(f):
print('{}: {}'.format(timeit.timeit(lambda: test(f), number=10),
f.__name__))
timetest(power_bit_length)
timetest(shift_bit_length)
timetest(power_log)
La ragione per cui sto usando range(1, 1000001)
invece di range(1000000)
è che la versione power_log
avrà esito negativo su 0
. La ragione per cui sto usando un piccolo numero di ripetizioni su un intervallo più ampio invece di un sacco di ripetizioni su un piccolo intervallo è perché mi aspetto che versioni diverse avranno prestazioni diverse su domini diversi. (Se vi aspettate di essere chiamata tale, con un gran numero mille bit, naturalmente, si desidera un test che utilizza quelli.)
con Apple Python 2.7.2:
4.38817000389: power_bit_length
3.69475698471: shift_bit_length
7.91623902321: power_log
Con Python.org Python 3.3.0:
6.566169916652143: power_bit_length
3.098236607853323: shift_bit_length
9.982460380066186: power_log
Con PyPy 1.9.0/2.7.2:
2.8580930233: power_bit_length
2.49524712563: shift_bit_length
3.4371240139: power_log
credo che questo dimostra che il 012.è la parte lenta qui; utilizzando bit_length
invece di log
si velocizzano le cose, ma l'utilizzo di 1<<
invece di 2**
è più importante.
Inoltre, penso che sia più chiaro. La versione dell'OP richiede di creare un contesto mentale: passare dai logaritmi ai bit e quindi tornare agli esponenti. Restare in bit per tutto il tempo (shift_bit_length
) o rimanere nei registri e negli esponenti (power_log
).
Si noti che il risultato è ** errato ** per' x == 0' , dal momento che '(-1) .bit_length() == 1' in Python. –
Presta attenzione alla precisione. 'math.log (2 ** 29,2)' è 29,000000000000004 quindi 'power_log (2 ** 29)' fornisce una risposta errata di 30. –
@ColonelPanic Il problema che hai notato è inesistente se 'math.log2' è usato, come dovrebbe essere giusto. Il problema esiste a partire da 29 solo se si utilizza 'math.log'. –