範囲はわかっているようです。もっと面白くするために、1<<20まで上がると仮定しましょう。
max_log2=20
したがって、(事実上)整数を2を底とする対数にマップするリストを作成します。以下はトリックを行います:
log2s_table=[0]*((1<<max_log2)+1)
for i in range(max_log2+1):
log2s_table[1<<i]=i
(これは、2の累乗ではない数値には何の役にも立ちません。問題の説明は、それらを処理する必要がないことを示しています。ただし、それを修正するのは簡単です。)
対数を取得する関数は非常に単純で、簡単にインライン化できます。
def table(v):
return log2s_table[v]
私が書いたテストコードが、サンプルのタイミングを取得するために使用されているものとまったく同じであることを保証することはできませんが、これはstringcount
コードよりもかなり高速です。
stringcount: 0.43 s.
table: 0.16 s.
テーブル内のすべての値が256未満であるため、リストの代わりに文字列を使用する方が速いのか、それともarray.array
バイト単位であるのか疑問に思いましたが、サイコロはありません。
string: 0.25 s.
arr: 0.21 s.
ルックアップを実行するためにを使用するdict
ことは、2の累乗のみがチェックされる方法を利用して、別の可能性です。
log2s_map=dict([(1<<x,x) for x in range(max_log2+1)])
def map(v):
return log2s_map[v]
ただし、この結果はそれほど良くありませんでした。
map: 0.20 s.
また、楽しみのためhex
に、floatオブジェクトのメソッドを使用して、数値の基数2の指数を(最後の部分として)含む文字列を取得することもできます。これは一般的に抽出するのに少し時間がかかりますが、指数が1桁になるだけの場合は、簡単に実行できます。
def floathex(v):
return ord(float(v).hex()[-1])-48
これは、競争力がなかったため、純粋にエンターテインメントの価値のためです。ただし、驚くべきことに、ビット単位のアプローチよりも高速です。
したがって、リストを使用するのが道のりのようです。
(このアプローチはメモリが限られているため、無制限にスケーリングすることはありませんが、それを補うために、実行速度はmax_log2
、Pythonコードを実行するときに気付くような方法で、または入力値に依存しません。メモリについて消費量、Pythonの内部を正しく覚えている場合(1<<max_log2)*4
、内容はすべて小さな整数であり、インタープリターが自動的にインターンするため、テーブルは約バイトを占有します。したがって、max_log2
が20の場合、約4MBになります。)