මෑතක් වන තුරුම මගේ පිළිතුර ජෝන් ස්කීට්ගේ කතාවට ඉතා සමීප වනු ඇත. කෙසේ වෙතත්, මම මෑතකදී හෑෂ් වගු දෙකක බලය භාවිතා කළ ව්යාපෘතියක් ආරම්භ කළෙමි, එනම් අභ්යන්තර වගුවේ ප්රමාණය 8, 16, 32 වැනි හැෂ් වගු ය. ප්රයිම් අංක ප්රමාණවලට අනුග්රහය දැක්වීමට හොඳ හේතුවක් තිබේ, නමුත් එහි ප්රමාණ දෙකේ බලයට ඇති වාසි කිහිපයක් ද වේ.
ඒක ගොඩක් උරා ගත්තා. ඒ නිසා ටිකක් අත්හදා බැලීම් හා පර්යේෂණ වලින් පසු මම පහත දැක්වෙන දෑ සමඟ මගේ හැෂ් නැවත සේදීමට පටන් ගතිමි:
public static int ReHash(int source)
{
unchecked
{
ulong c = 0xDEADBEEFDEADBEEF + (ulong)source;
ulong d = 0xE2ADBEEFDEADBEEF ^ c;
ulong a = d += c = c << 15 | c >> -15;
ulong b = a += d = d << 52 | d >> -52;
c ^= b += a = a << 26 | a >> -26;
d ^= c += b = b << 51 | b >> -51;
a ^= d += c = c << 28 | c >> -28;
b ^= a += d = d << 9 | d >> -9;
c ^= b += a = a << 47 | a >> -47;
d ^= c += b << 54 | b >> -54;
a ^= d += c << 32 | c >> 32;
a += d << 25 | d >> -25;
return (int)(a >> 1);
}
}
ඊට පස්සේ මගේ බලය දෙකේ හැෂ් මේසය තවත් උරා ගත්තේ නැහැ.
මෙය මට බාධාවක් විය, මන්ද ඉහත සඳහන් දෑ ක්රියාත්මක නොවිය යුතුය. නැතහොත් වඩාත් නිවැරදිව කිවහොත්, මුල් පිටපත GetHashCode()
විශේෂිත ආකාරයකින් දුප්පත් නම් මිස එය ක්රියා නොකළ යුතුය .
හැෂ් කේතයක් නැවත මිශ්ර කිරීමෙන් විශාල හැෂ් කේතයක් වැඩි දියුණු කළ නොහැක, මන්ද එකම බලපෑම වන්නේ අපි තවත් isions ට්ටන කිහිපයක් හඳුන්වා දීමයි.
හැෂ් කේතයක් නැවත මිශ්ර කිරීමෙන් භයානක හැෂ් කේතයක් වැඩිදියුණු කළ නොහැක, මන්ද එකම ප්රති effect ලය වන්නේ උදා. 53 වන අගය මත ගැටීම් විශාල සංඛ්යාවක් 18,3487,291 වටිනාකමට වෙනස් කිරීමයි.
හැෂ් කේතය නැවත මිශ්ර පමණක් එහි පරාසය (2 පුරා නිරපේක්ෂ ගැටීම් අවම වශයෙන් තරමක් හොඳින් කළ හැෂ් කේතය වැඩි දියුණු කළ හැකි 32 හැකි අගයන්) නමුත් දරුණු ලෙස හැෂ් වගුවේ සැබෑ භාවිතය සඳහා වසා modulo'd විට ගැටීම් දී. බල-දෙකේ වගුවක සරල මොඩියුලය මෙය වඩාත් පැහැදිලිව පෙනෙන අතර, එය වඩාත් පොදු ප්රාථමික සංඛ්යා වගු සමඟ negative ණාත්මක බලපෑමක් ඇති කරයි, එය එතරම් පැහැදිලිව පෙනෙන්නට නොතිබුණි (නැවත සකස් කිරීමේ අමතර කාර්යය ප්රතිලාභයට වඩා වැඩි වනු ඇත , නමුත් ප්රතිලාභ තවමත් පවතී).
සංස්කරණය කරන්න: මම විවෘත ලිපින භාවිතා කරමින් සිටියෙමි, එමඟින් ision ට්ටනයට සංවේදීතාවද වැඩි වනු ඇත, සමහර විට එය බලය දෙකේ බලයට වඩා වැඩි ය.
.නෙට් හි (හෝ මෙහි අධ්යයනය ) string.GetHashCode()
ක්රියාත්මක කිරීම මේ ආකාරයෙන් වැඩිදියුණු කළ හැකිද යන්න කනස්සල්ලට කරුණකි ( අඩු ගැටුම් හේතුවෙන් පරීක්ෂණ 20-30 ගුණයක් වේගයෙන් ධාවනය වන අනුපිළිවෙල අනුව) සහ මගේම හැෂ් කේත කොතරම්ද? වැඩිදියුණු කළ හැකිය (ඊට වඩා බොහෝ දේ).
මම අතීතයේ කේත කරන ලද සහ ඇත්ත වශයෙන්ම මෙම වෙබ් අඩවියේ පිළිතුරු වල පදනම ලෙස භාවිතා කරන ලද සියලු GetHashCode () ක්රියාත්මක කිරීම් මා සිතුවාට වඩා නරක ය . බොහෝ විට එය බොහෝ භාවිතයන් සඳහා "ප්රමාණවත්" විය, නමුත් මට වඩා හොඳ යමක් අවශ්ය විය.
ඒ නිසා මම එම ව්යාපෘතිය එක් පැත්තකට දැමුවෙමි (එය කෙසේ හෝ සුරතල් ව්යාපෘතියක් විය) .NET හි හොඳ, හොඳින් බෙදා හරින ලද හැෂ් කේතයක් ඉක්මනින් නිෂ්පාදනය කරන්නේ කෙසේදැයි සොයා බැලීමට පටන් ගතිමි.
අවසානයේදී මම ස්පූකි හැෂ් .NET වෙත ගෙන ඒමට කටයුතු කළෙමි . ඇත්ත වශයෙන්ම ඉහත කේතය 32-බිට් ආදානයකින් බිට් 32 ප්රතිදානයක් නිපදවීමට ස්පූකි හැෂ් භාවිතා කිරීමේ වේගවත් අනුවාදයකි.
දැන්, ස්පූකි හැෂ් කේත කෑල්ලක් මතක තබා ගැනීමට ඉක්මන් නොවේ. මගේ වරාය ඊටත් වඩා අඩු නිසා වඩා හොඳ වේගය සඳහා මම එය බොහෝමයක් අතින් ලියා ඇත. නමුත් කේත නැවත භාවිතා කිරීම යනු එයයි.
ඉන්පසුව මම එම ව්යාපෘතිය එක් පැත්තකට තැබුවෙමි , මන්ද මුල් ව්යාපෘතිය මඟින් වඩා හොඳ හැෂ් කේතයක් නිෂ්පාදනය කරන්නේ කෙසේද යන ප්රශ්නය නිපදවා ඇති හෙයින් එම ව්යාපෘතිය වඩා හොඳ .නෙට් මතක සටහනක් නිෂ්පාදනය කරන්නේ කෙසේද යන ප්රශ්නය ඇති කළේය.
පසුව මම නැවත පැමිණ, ස්වදේශීය වර්ග සියල්ලම (except හැර decimal
) පහසුවෙන් හැෂ් කේතයකට පෝෂණය කිරීම සඳහා අධික බරක් නිෂ්පාදනය කළෙමි .
එය වේගවත් ය, බොබ් ජෙන්කින්ස් බොහෝ ගෞරවය ලැබීමට සුදුසු වන්නේ මා විසින් ගෙන එන ලද ඔහුගේ මුල් කේතය තවමත් වේගවත් බැවින්, විශේෂයෙන් ඇල්ගොරිතම for සඳහා ප්රශස්තිකරණය කර ඇති බිට් 64 යන්ත්රවල ය.
සම්පූර්ණ කේතය https://bitbucket.org/JonHanna/spookilysharp/src හි දැකිය හැකි නමුත් ඉහත කේතය එහි සරල කළ අනුවාදයක් ලෙස සලකන්න.
කෙසේ වෙතත්, එය දැන් දැනටමත් ලියා ඇති බැවින්, කෙනෙකුට එය වඩාත් පහසුවෙන් භාවිතා කළ හැකිය:
public override int GetHashCode()
{
var hash = new SpookyHash();
hash.Update(field1);
hash.Update(field2);
hash.Update(field3);
return hash.Final().GetHashCode();
}
එය බීජ අගයන් ද ගනී, එබැවින් ඔබට විශ්වාස කළ නොහැකි ආදානය සමඟ කටයුතු කිරීමට අවශ්ය නම් සහ හැෂ් ඩොස් ප්රහාර වලින් ආරක්ෂා වීමට අවශ්ය නම් ඔබට අතිකාල හෝ ඒ හා සමාන බීජයක් සැකසිය හැකි අතර ප්රහාරකයන් විසින් ප්රති results ල අනපේක්ෂිත කළ හැකිය:
private static long hashSeed0 = Environment.TickCount;
private static long hashSeed1 = DateTime.Now.Ticks;
public override int GetHashCode()
{
//produce different hashes ever time this application is restarted
//but remain consistent in each run, so attackers have a harder time
//DoSing the hash tables.
var hash = new SpookyHash(hashSeed0, hashSeed1);
hash.Update(field1);
hash.Update(field2);
hash.Update(field3);
return hash.Final().GetHashCode();
}
* මෙහි ඇති විශාල පුදුමය නම් (x << n) | (x >> -n)
වැඩිදියුණු කළ දේවල් ආපසු ලබා දෙන භ්රමණ ක්රමයක් අතින් ඇලවීමයි . විහිළුකාරයා මා වෙනුවෙන් එය යොමු කරනු ඇතැයි මට විශ්වාසයි, නමුත් පැතිකඩ වෙනත් ආකාරයකින් පෙන්නුම් කරයි.
N decimal
.NET දෘෂ්ටිකෝණයෙන් C # වලින් ආවත් එය ස්වදේශීය නොවේ. එහි ඇති ගැටළුව නම්, තමන් විසින්ම GetHashCode()
නිරවද්යතාව සැලකිය යුතු ලෙස සලකන අතර එය තමන්ගේම Equals()
නොවේ. දෙකම වලංගු තේරීම් වේ, නමුත් ඒ හා සමාන නොවේ. ඔබේම අනුවාදය ක්රියාත්මක කිරීමේදී, ඔබ එකක් හෝ වෙනත් දෙයක් කිරීමට තෝරා ගත යුතුය, නමුත් ඔබට අවශ්ය කුමක්දැයි මට දැනගත නොහැක.
. සංසන්දනය කිරීමෙන්. නූලක් මත භාවිතා කරන්නේ නම්, බිට් 64 හි ඇති ස්පූකි හැෂ් බිටු string.GetHashCode()
32 ට වඩා සැලකිය යුතු වේගයකින් යුක්ත වන අතර එය string.GetHashCode()
බිට් 64 ට වඩා තරමක් වේගවත් වන අතර එය බිටු 32 හි ස්පූකි හැෂ් වලට වඩා සැලකිය යුතු වේගයකින් යුක්ත වුවද සාධාරණ තේරීමක් කිරීමට තරම් වේගවත් වුවද.
GetHashCode
. එය අන් අයට ප්රයෝජනවත් වේ යැයි මම බලාපොරොත්තු වෙමි. එරික් Lippert විසින් ලියන GetHashCode සඳහා මාර්ගෝපදේශ හා නීති