সাম্প্রতিক অবধি আমার উত্তর এখানে জোন স্কিটের খুব কাছাকাছি থাকত। যাইহোক, আমি সম্প্রতি একটি প্রকল্প শুরু করেছি যা পাওয়ার-অফ-টু হ্যাশ টেবিল ব্যবহার করেছে, সেটি হ্যাশ টেবিল যেখানে অভ্যন্তরীণ টেবিলের আকার 8, 16, 32, ইত্যাদি রয়েছে prime প্রাইম-সংখ্যা আকারের পক্ষে নেওয়ার পক্ষে যুক্তিসঙ্গত কারণ রয়েছে তবে সেখানে রয়েছে পাওয়ার-অফ-টু মাপের কিছু সুবিধা।
এবং এটি বেশ কিছুটা চুষে ফেলেছে। তাই কিছুটা পরীক্ষা-নিরীক্ষা ও গবেষণার পরে আমি নিম্নলিখিতগুলি দিয়ে আমার হ্যাশগুলিকে পুনরায় হ্যাশ করতে শুরু করেছি:
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()
খুব নির্দিষ্ট উপায়ে দরিদ্র না হত।
একটি হ্যাশকোড পুনরায় মেশানো একটি দুর্দান্ত হ্যাশকোড উন্নত করতে পারে না, কারণ একমাত্র সম্ভাব্য প্রভাবটি হ'ল আমরা আরও কয়েকটি সংঘর্ষের পরিচয় দিই।
একটি হ্যাশ কোডটি পুনরায় মিশ্রণ একটি ভয়ানক হ্যাশ কোডটিকে উন্নত করতে পারে না, কারণ কেবলমাত্র সম্ভাব্য প্রভাবটি হ'ল উদাহরণস্বরূপ, 53 মানের একটি বিশাল সংখ্যক সংঘর্ষের একটি বড় সংখ্যার মান 18,3487,291।
একটি হ্যাশ কোডটি পুনরায় মিশ্রিত করা কেবলমাত্র একটি হ্যাশ কোডকে উন্নত করতে পারে যা তার পরিসীমা জুড়ে নিখুঁত সংঘর্ষগুলি এড়িয়ে চলার ক্ষেত্রে কমপক্ষে বেশ ভাল করেছে (2 32 সম্ভাব্য মানগুলি) তবে হ্যাশ টেবিলের প্রকৃত ব্যবহারের জন্য মডুলুড হয়ে গেলে সংঘর্ষগুলি এড়ানোতে খারাপ। পাওয়ার-টু-টেবিলের সরল মডুলো এটিকে আরও প্রকট করে তুলেছে, তবুও এটি আরও সাধারণ প্রাইম-সংখ্যা টেবিলগুলির সাথে নেতিবাচক প্রভাব ফেলছিল, এটি ঠিক তেমন স্পষ্ট ছিল না (পুনর্নির্মাণের অতিরিক্ত কাজ উপকারের চেয়েও বেশি হবে) , তবে সুবিধাটি এখনও থাকবে)।
সম্পাদনা: আমি ওপেন-এড্রেসিংও ব্যবহার করছিলাম, যা সংঘর্ষের সংবেদনশীলতাও বাড়িয়ে তুলত, সম্ভবত এটি পাওয়ার-টু-এর চেয়ে বেশি ছিল।
এবং ভাল, এটি নেট (বা এখানে অধ্যয়ন ) এর string.GetHashCode()
বাস্তবায়নগুলি কতটা উন্নত হতে পারে (কম সংঘর্ষের কারণে প্রায় 20-30 গুণ দ্রুত চলমান পরীক্ষার ক্রমে) এবং আমার নিজের হ্যাশ কোডগুলি কতটা বিঘ্নিত করছে তা বিরক্ত করছিল উন্নত করা যেতে পারে (এর চেয়ে অনেক বেশি)।
সকল GetHashCode () বাস্তবায়নের আমি অতীতে কোডেড ছিলাম, এবং প্রকৃতপক্ষে এই সাইটে উত্তর ভিত্তি হিসেবে ব্যবহার করা হয়, অনেক খারাপ চেয়ে আমি throught চাই ছিল । বেশিরভাগ সময় ব্যবহারের জন্য এটি "যথেষ্ট ভাল" ছিল তবে আমি আরও ভাল কিছু চাইছিলাম।
সুতরাং আমি সেই প্রকল্পটি একদিকে রাখলাম (এটি যাইহোক পোষা প্রাণীর প্রকল্প ছিল) এবং কীভাবে। নেট এ খুব ভাল, ভাল বিতরণ করা হ্যাশ কোড উত্পাদন করা যায় তা সন্ধান করতে শুরু করি।
শেষ পর্যন্ত আমি স্পোকিহ্যাশ । নেট এ পোর্ট করার বিষয়ে স্থির হয়েছি । প্রকৃতপক্ষে উপরের কোডটি 32-বিট ইনপুট থেকে 32-বিট আউটপুট উত্পাদন করতে স্পুকিহ্যাশ ব্যবহারের একটি দ্রুতগতির সংস্করণ।
এখন, স্পুকিহ্যাশ কোডের টুকরোগুলি মনে রাখা খুব ভাল নয়। আমার এটির বন্দরটি আরও কম কারণ আমি আরও ভাল গতির জন্য এটির অনেকগুলি হাত-linedোকানো। তবে কোড পুনরায় ব্যবহারের জন্য এটিই।
তারপরে আমি সেই প্রকল্পটিকে একদিকে রাখলাম , কারণ মূল প্রকল্পটি যেমন একটি উন্নত হ্যাশ কোড তৈরি করতে পারে তার প্রশ্ন উত্থাপন করেছিল, সুতরাং সেই প্রকল্পটি কীভাবে আরও ভাল .NET মেমকিপি উত্পাদন করতে পারে সে প্রশ্নটি উত্থাপন করেছিল।
তারপরে আমি ফিরে আসলাম এবং খুব সহজেই প্রায় সমস্ত দেশীয় ধরণের (except ব্যতীত decimal
) একটি হ্যাশ কোডে ফিড দেওয়ার জন্য প্রচুর ওভারলোড উত্পাদন করেছি ।
এটি দ্রুত, যার জন্য বব জেনকিন্স বেশিরভাগ কৃতিত্বের দাবিদার, কারণ আমি যে মূল কোডটি দিয়েছিলাম তার মূল কোডটি এখনও দ্রুততর, বিশেষত 64৪-বিট মেশিনে যা g এর জন্য অনুকূলিত হয়েছে ‡
সম্পূর্ণ কোডটি 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();
}
এটি বীজের মানও গ্রহণ করে, সুতরাং আপনার যদি অবিশ্বস্ত ইনপুট নিয়ে কাজ করতে হয় এবং হ্যাশ ডস আক্রমণ থেকে রক্ষা করতে চান আপনি আপটাইম বা অনুরূপের উপর ভিত্তি করে একটি বীজ সেট করতে পারেন এবং আক্রমণকারীদের দ্বারা ফলাফলটিকে অনির্দেশ্য করতে পারেন:
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)
উন্নত জিনিসগুলি ফিরিয়ে দিয়েছে । আমি নিশ্চিত থাকতে পারি যে জিটারটি আমার পক্ষে এটির অন্তর্ভুক্ত ছিল তবে প্রোফাইলিং অন্যথায় প্রদর্শিত হয়েছিল।
† decimal
.NET দৃষ্টিকোণ থেকে নেটিভ যদিও তা থেকে C # এর নয়। এটা দিয়ে সমস্যা যে তার নিজের GetHashCode()
গুরুত্বপূর্ণ হিসাবে একইরূপে স্পষ্টতা যখন নিজস্ব Equals()
না। উভয়ই বৈধ পছন্দ, তবে এর মতো মিশ্রিত নয়। আপনার নিজস্ব সংস্করণটি প্রয়োগ করার ক্ষেত্রে আপনার একটি বা অন্যটি বেছে নেওয়া দরকার, তবে আপনি কী চান তা আমি জানতে পারি না।
Comparison তুলনা করার উপায় দ্বারা। যদি স্ট্রিংয়ে ব্যবহার করা হয়, তবে string.GetHashCode()
32 বিটের string.GetHashCode()
তুলনায় স্পোকি হ্যাশ 32 বিটের তুলনায় যথেষ্ট দ্রুত যা 32 বিটের তুলনায় স্পুকিহ্যাশের তুলনায় যথেষ্ট দ্রুত, যদিও যুক্তিসঙ্গত পছন্দ হিসাবে যথেষ্ট দ্রুত।
GetHashCode
। আমি আশা করি এটি অন্যদের জন্য সহায়ক হবে। নির্দেশিকা এবং GetHashCode জন্য নিয়ম এরিক Lippert দ্বারা লিখিত