文字列を受け取り、0 から 1 までの数値を返す関数を作成したいと考えています。関数は、同じ文字列が与えられたときに一貫して同じ数値を返す必要がありますが、それ以外の結果には識別可能なパターンがあってはなりません。入力文字列の大規模なセットの出力数値は、均一な分布に従う必要があります。
さらに、そのような関数を複数生成する必要があります。つまり、文字列「abc」を指定すると、関数 A は一貫して 0.593927 を返し、関数 B は一貫して 0.0162524 を返す可能性があります。私はそれが高速である必要があり(数値シミュレーション用です)、適度に優れた統計が必要です。
私は Python を使用しており、「Python ライブラリを使用して簡単に実行する方法は次のとおりです」または「実装できるアルゴリズムは次のとおりです」という形式の回答で解決します。Python ですばやく実行する方法がない場合は、代わりに C に切り替えます。
次の 2 つの方法のどちらでも機能することはわかっていますが、それぞれに欠点があるため、より洗練されたソリューションを探したいと思います。
辞書
を保存する 新しい文字列が与えられるたびに新しい乱数を計算し、それを辞書に保存して、同じ文字列を再度受け取ったときに取得できるようにします。ただし、私のアプリケーションは、1 回しか表示されない文字列を大量に生成する可能性が高く、最終的には非常に大きな辞書をメモリに格納する必要があります。また、同じシードを使用しても、同じ文字列を異なる順序で受け取ると、異なる関数を生成するため、再現性がより難しくなります。これらの理由から、「その場で」乱数を一貫して計算する方がはるかに優れています。ハッシュ関数を使用
して、文字列に対してハッシュ関数を呼び出すだけで、結果を数値に変換できます。複数の関数を生成する問題は、たとえば、すべての入力文字列に「シード」文字列を追加することで解決できます。でも、その後、適切な速度と統計を持つハッシュ関数を見つけようとすることに固執しています。Python のビルトイン ハッシュは高速ですが、実装に依存します。また、この種の目的のために設計されていないため、統計がどれほど優れているかはわかりません。一方で、md5 などの安全なハッシュ アルゴリズムを使用することもできますが、これは優れた統計情報を提供しますが、これは私のアプリケーションには遅すぎます。通常、データ ストレージ アプリケーション向けのハッシュ関数は、md5 などの暗号的に安全な関数よりもはるかに高速ですが、均一に分散された出力を生成するのではなく、衝突を回避することを目的として設計されており、これらはすべての場合で必ずしも同じではありません。
ハッシュ関数に関する追加の注意事項
衝突を回避することと均一な結果を生成することは別物であることを説明するために、Python の組み込みハッシュ関数を使用した次の例を検討してください。
>>> hash("aaa") % 1000
340
>>> hash("aab") % 1000
343
>>> hash("aac") % 1000
342
>>> hash("aad") % 1000
337
>>> hash("aae") % 1000
336
>>> hash("aaf") % 1000
339
>>> hash("aag") % 1000
338
>>> hash("aah") % 1000
349
>>> hash("aai") % 1000
348
>>> hash("aaj") % 1000
351
>>> hash("aak") % 1000
350
上記の出力には衝突はありませんが、それらはすべて 336 から 351 の間にあり、3 桁目に明確なパターンがあるため、明らかに均一に分布していません。そうすれば、おそらくより良い統計を取得できると(hash("aaa")/HASH_MAX)*1000
思いますが(どうあるべきかを理解できると仮定してHASH_MAX
)、これは、優れたハッシュ関数の要件が探している関数の要件と同じではないことを示すのに役立つはずです.
問題に関するいくつかの関連情報
文字列はシミュレーションによって生成されるため、このアルゴリズムが機能する必要がある文字列が何であるかは正確にはわかりませんが、次のような場合が考えられます。
それらの文字セットは非常に制限されています (おそらく 4 つまたは 5 つの異なる記号のみ)。
さまざまな長さの、多くのユニークまたは珍しい文字列といくつかの非常に一般的な文字列があります。
文字列の長さに上限はありませんが、短いものは長いものよりもはるかに一般的です。100 文字を超えるものを見たことがなくても驚かないでしょうが、確かなことはわかりません。それらの多くは 1 ~ 3 文字しかないため、アルゴリズムが短い文字列に対して高速であることが重要です。(しかし、特定の長さ未満の文字列にはルックアップテーブルを使用できると思います。)
通常、文字列には共通の大きな部分文字列があります。多くの場合、2 つの文字列の違いは、最初または最後に追加された 1 文字だけです。文字列が類似している場合、アルゴリズムが類似した出力値を与える傾向がないことが重要です。