0

次のC#ハッシュ関数(SOにもあります!)があります。これは、いくつかの異なるプラットフォームをカバーする一連のアプリで使用しています。

public static int GetStableHash(string s, int hashlength)
{
    uint hash = 0;
    var bytes = System.Text.Encoding.ASCII.GetBytes(s);
    foreach (byte b in bytes)
    {
        hash += b;
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    // final avalanche
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);

    return (int)(hash % hashlength);
}

私はそれをJavascriptに移植しようとしています。そこでは、別のアプリが一致するハッシュを生成します。唯一の問題は、JSにuintタイプがなく、ビット単位の計算を実行する前に、内部でintをfloatに変換しているように見えることです。これにより、この移植された関数で問題が発生しています。

function getStableHash(s, hashlength)
{
    var hash = 0;
    var bytes = stringToBytes(s);   // this function just grabs a byte array for the given input string
    for (var i = 0; i < bytes.length; i++)
    {
        hash += bytes[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    // final avalanche
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);

    return Math.round(hash % hashlength);
}

上記のコードでは、シフトによって符号ビットが存在するために問題が発生し、結果のハッシュがC#バージョンの出力と一致しません。他のさまざまなSO投稿(たとえば、大きな整数を使用したビット演算を参照)から、これを解決するための最良の方法が何であるかは不明です。

C#およびC ++のハッシュメソッドを使用するコードはすでに本番環境にあるため、Javascriptの欠点に対応するためにハッシュメソッドを他の場所に変更することはできません。

JSの内部型変換を回避するにはどうすればよいですか?

4

1 に答える 1

2

次のことを試してください。

  1. >>>符号付きではなく符号なし右シフトを使用する

  2. モジュロを取得する前に、最終結果をunsigned 32 ビット int に>>> 0変換するために使用します。

    return (hash >>> 0) % hashlength;

于 2013-03-11T00:44:43.777 に答える