pythonで、少なくとも4ビットの出力を持つ整数を生成する高性能の文字列ハッシュ関数が必要です(64ビットは理にかなっていますが、32は少なすぎます)。 Stack Overflowには、このような他のいくつかの質問がありますが、私が見つけたすべての受け入れられた/賛成された回答の中で、(与えられた理由で)当てはまらないいくつかのカテゴリの1つに分類されました。
hash()
関数を使用します。この関数は、少なくとも私が開発しているマシンでは(python 2.7、および64ビットCPUを使用) 32ビット以内に収まる整数を生成します-私の目的には十分な大きさではありません。string.__hash__()
関数をプロトタイプとして使用して、独自の関数を作成します。この特定の関数の効率がc_mulの使用にあることを除いて、これが正しい方法だと思います。 32ビットをラップする関数-繰り返しますが、私が使用するには小さすぎます!非常にイライラします、それは完璧にとても近いです!理想的なソリューションは、次の特性を、比較的重要度の低い順に持っています。
「摂動」ハッシュの例。ハッシュ値は小さな整数値nによって大幅に変更されます。
def perturb_hash(key,n):
return hash((key,n))
最後に、私が何をしているのか知りたい場合は、そのような特定のハッシュ関数が必要です。パフォーマンスを大幅に向上させるために、pybloomモジュールを完全に書き直しています。私はそれで成功しました(今では約4倍速く実行され、スペースの約50%を使用します)が、フィルターが十分に大きくなると、突然偽陽性率が急上昇することに気づきました。ハッシュ関数が十分なビットをアドレス指定していなかったためだと気づきました。 32ビットは40億ビットしかアドレス指定できず(フィルターはバイトではなくビットをアドレス指定します)、ゲノムデータに使用しているフィルターの一部はその2倍以上(したがって最小34ビット)です。
ありがとう!
MurmurHash3の128ビットバリアント を見てください。 アルゴリズムのページ にはいくつかのパフォーマンス数値が含まれています。これをPythonに、純粋に、またはC拡張として移植できるはずです。 (更新作成者は、128ビットバリアントを使用し、不要なビットを破棄することをお勧めします)。
MurmurHash2 64ビットが機能する場合は、 pyfasthashパッケージ にPython実装(C拡張)があります。これには、他のいくつかの非暗号化ハッシュバリアントが含まれています。これらのいくつかは32ビット出力しか提供しませんが。
UpdateMurmur3ハッシュ関数のクイックPythonラッパーを実行しました。 Githubプロジェクトはここにあります =そしてあなたはそれを Python Package Indexも で見つけることができます;それはビルドするためにC++コンパイラを必要とするだけです;ブーストは必要ありません。
使用例とタイミング比較:
import murmur3
import timeit
# without seed
print murmur3.murmur3_x86_64('samplebias')
# with seed value
print murmur3.murmur3_x86_64('samplebias', 123)
# timing comparison with str __hash__
t = timeit.Timer("murmur3.murmur3_x86_64('hello')", "import murmur3")
print 'murmur3:', t.timeit()
t = timeit.Timer("str.__hash__('hello')")
print 'str.__hash__:', t.timeit()
出力:
15662901497824584782
7997834649920664675
murmur3: 0.264422178268
str.__hash__: 0.219163894653
組み込みのhash()関数を使用します。この関数は、少なくとも私が開発しているマシン(python 2.7、および64ビットCPU)では、32ビット内に収まる整数を生成します-私の目的には十分な大きさではありません。
それは真実ではない。組み込みのハッシュ関数は、64ビットシステムで64ビットハッシュを生成します。
これはpython str hashing function from Objects/stringobject.c
(Pythonバージョン2.7):
static long
string_hash(PyStringObject *a)
{
register Py_ssize_t len;
register unsigned char *p;
register long x; /* Notice the 64-bit hash, at least on a 64-bit system */
if (a->ob_shash != -1)
return a->ob_shash;
len = Py_SIZE(a);
p = (unsigned char *) a->ob_sval;
x = *p << 7;
while (--len >= 0)
x = (1000003*x) ^ *p++;
x ^= Py_SIZE(a);
if (x == -1)
x = -2;
a->ob_shash = x;
return x;
}
「文字列」:ハッシュPython 2.x str
オブジェクトおよび/またはPython3.xbytes
および/またはbytearray
オブジェクト。
これは最初の制約に違反する可能性がありますが、次のようなものの使用を検討してください。
(zlib.adler32(strg, perturber) << N) ^ hash(strg)
(32 + N)ビットハッシュを取得します。
組み込みのハッシュ関数に注意してください!
Python3以降、インタープリターが起動するたびに異なるシードが供給されるため(詳細はわかりません)、毎回異なる値が生成されますが、ネイティブの数値型では生成されません。
$ python3 -c 'print(hash("Hello!"), hash(3.14))'
-1756730906053498061 322818021289917443
$ python3 -c 'print(hash("Hello!"), hash(3.14))'
-4556027264747844925 322818021289917443
$ python3 -c 'print(hash("Hello!"), hash(3.14))'
-4403217265550417031 322818021289917443
Python 3.2を使用できる場合、64ビットWindowsでのハッシュ結果は64ビット値になります。