কোন পূর্ণসংখ্যার হ্যাশ ফাংশনটি ভাল যা কোনও পূর্ণসংখ্যার হ্যাশ কী গ্রহণ করে?
উত্তর:
নুথের গুণক পদ্ধতি:
hash(i)=i*2654435761 mod 2^32
সাধারণভাবে, আপনার এমন একটি গুণক বেছে নেওয়া উচিত যা আপনার হ্যাশের আকারের ( 2^32
যেমন উদাহরণের) ক্রমযুক্ত এবং এতে কোনও সাধারণ কারণ নেই। এইভাবে হ্যাশ ফাংশনটি আপনার সমস্ত হ্যাশ স্থানটি সমানভাবে কভার করে।
সম্পাদনা করুন: এই হ্যাশ ফাংশনের বৃহত্তম অসুবিধা হ'ল এটি বিভাজ্যতা সংরক্ষণ করে, সুতরাং আপনার পূর্ণসংখ্যাগুলি যদি 2 বা 4 দ্বারা বিভাজ্য হয় (যা অস্বাভাবিক নয়) তবে তাদের হ্যাশগুলিও হবে। এটি হ্যাশ টেবিলগুলির একটি সমস্যা - আপনি কেবল বালতি ব্যবহারের 1/1 বা 1/4 টি দিয়ে শেষ করতে পারেন।
আমি নিম্নলিখিত আলগোরিদিম একটি খুব ভাল পরিসংখ্যান বিতরণ সরবরাহ করে। প্রতিটি ইনপুট বিট প্রায় 50% সম্ভাব্যতা সহ প্রতিটি আউটপুট বিটকে প্রভাবিত করে। কোনও সংঘর্ষ নেই (প্রতিটি ইনপুট ফলাফল ভিন্ন আউটপুট)। সিপিইউতে অন্তর্নির্মিত পূর্ণসংখ্যা গুণক একক না থাকলে ব্যতীত অ্যালগরিদম দ্রুত। সি কোড, অভিমানী int
32 বিট (জাভা জন্য, প্রতিস্থাপন হয় >>
সঙ্গে >>>
এবং অপসারণ unsigned
):
unsigned int hash(unsigned int x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
স্বাধীনতার স্বাধীনতা , বহু ঘন্টার জন্য চলমান একটি বিশেষ মাল্টি-থ্রেডেড টেস্ট প্রোগ্রাম ব্যবহার করে ম্যাজিক নম্বরটি গণনা করা হয়েছিল , যা হিমস্রাবের প্রভাব গণনা করে (একক ইনপুট বিট পরিবর্তিত হলে আউটপুট বিটের সংখ্যা যে গড়ে প্রায় 16 হওয়া উচিত), স্বাধীনতা আউটপুট বিট পরিবর্তন (আউটপুট বিট একে অপরের উপর নির্ভর করে না), এবং যদি কোনও ইনপুট বিট পরিবর্তন হয় তবে প্রতিটি আউটপুট বিটে পরিবর্তনের সম্ভাবনা। গণনা করা মান 32-বিট দ্বারা ব্যবহৃত finalizer চেয়ে ভাল MurmurHash এবং প্রায় ভাল (পুরোপুরি) যখন ব্যবহার যত হবে AES । সামান্য সুবিধা হ'ল একই ধ্রুবকটি দু'বার ব্যবহৃত হয় (এটি শেষবার যখন আমি পরীক্ষা করেছি তখন এটি কিছুটা দ্রুত হয়েছে, এটি এখনও ঘটছে কিনা তা নিশ্চিত নয়)।
আপনি প্রক্রিয়াটি বিপরীত করতে পারেন (হ্যাশ থেকে ইনপুট মান পাবেন) যদি আপনি এর 0x45d9f3b
সাথে 0x119de1f3
( গুণিত বিপরীত ) প্রতিস্থাপন করেন :
unsigned int unhash(unsigned int x) {
x = ((x >> 16) ^ x) * 0x119de1f3;
x = ((x >> 16) ^ x) * 0x119de1f3;
x = (x >> 16) ^ x;
return x;
}
-৪-বিট সংখ্যার জন্য, আমি নিম্নলিখিতটি ব্যবহার করার পরামর্শ দিই, এমনকি ভেবেছিলাম এটি সম্ভবত দ্রুত নয়। এইটি স্প্লিটমিক্স 64৪ এর উপর ভিত্তি করে তৈরি হয়েছে যা মনে হয় ব্লগার আর্টিকেল বেটার বিট মিক্সিংয়ের (মিক্স ১৩) উপর ভিত্তি করে ।
uint64_t hash(uint64_t x) {
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
x = x ^ (x >> 31);
return x;
}
জাভা, ব্যবহারের জন্য long
যোগ, L
ধ্রুবক হয়, প্রতিস্থাপন >>
সঙ্গে >>>
এবং অপসারণ unsigned
। এই ক্ষেত্রে, বিপরীতকরণ আরও জটিল:
uint64_t unhash(uint64_t x) {
x = (x ^ (x >> 31) ^ (x >> 62)) * UINT64_C(0x319642b2d24d8ec3);
x = (x ^ (x >> 27) ^ (x >> 54)) * UINT64_C(0x96de1b173f119089);
x = x ^ (x >> 30) ^ (x >> 60);
return x;
}
আপডেট: আপনি হ্যাশ ফাংশন প্রসপেক্টর প্রকল্পটিও দেখতে চাইতে পারেন , যেখানে অন্যান্য (সম্ভবত আরও ভাল) স্থির তালিকাভুক্ত রয়েছে।
আপনার ডেটা কীভাবে বিতরণ করা হবে তার উপর নির্ভর করে। একটি সাধারণ কাউন্টার জন্য, সহজতম ফাংশন
f(i) = i
ভাল হবে (আমি অনুকূল সন্দেহ করি, তবে আমি এটি প্রমাণ করতে পারি না)।
দ্রুত এবং ভাল হ্যাশ ফাংশনগুলিকে কম গুণাবলীর মতো দ্রুত নির্গমন থেকে রচনা করা যেতে পারে
র্যান্ডম সংখ্যা জেনারেশনের জন্য পিসিজি দিয়ে প্রদর্শিত যেমন উন্নত গুণাবলীর সাথে একটি হ্যাশিং ফাংশন উপস্থাপন করা ।
এটি আসলে rrxmrrxxx_0 এবং মুরমার হ্যাশটি জেনে বা অজান্তে ব্যবহার করছে recipe
আমি ব্যক্তিগতভাবে খুঁজে পেয়েছি
uint64_t xorshift(const uint64_t& n,int i){
return n^(n>>i);
}
uint64_t hash(const uint64_t& n){
uint64_t p = 0x5555555555555555ull; // pattern of alternating 0 and 1
uint64_t c = 17316035218449499591ull;// random uneven integer constant;
return c*xorshift(p*xorshift(n,32),32);
}
যথেষ্ট ভাল হতে।
একটি ভাল হ্যাশ ফাংশন করা উচিত
আসুন প্রথমে পরিচয় ফাংশনটি দেখুন। এটি সন্তুষ্ট 1. তবে নয় 2:
ইনপুট বিট এন 100% (লাল) এবং অন্য কারও সাথে সম্পর্কিত না করে আউটপুট বিট এন নির্ধারণ করে, এগুলি তাই নীল, একেবারে নিখুঁত লাল রেখা সরবরাহ করে।
একটি xorshift (এন, 32) খুব ভাল হয় না, দেড় লাইনের ফলন দেয়। তবু সন্তুষ্ট 1., কারণ এটি দ্বিতীয় প্রয়োগের সাথে অবিচ্ছিন্ন।
স্বাক্ষরবিহীন পূর্ণসংখ্যার সাথে একটি গুণটি আরও ভাল, আরও দৃ strongly়ভাবে ক্যাসকেড করা এবং 0.5 এর সম্ভাব্যতার সাথে আরও আউটপুট বিটগুলি উল্টানো, যা আপনি চান, সবুজ in এটি 1 টি সন্তুষ্ট করে প্রতিটি অসম পূর্ণসংখ্যার জন্য একটি গুণক বিপরীত থাকে।
দুটি সংমিশ্রণ নিম্নলিখিত আউটপুট দেয়, এখনও সন্তুষ্ট 1। দুটি দ্বি দ্বিপ্রদীপক ফাংশন গঠনের ফলে আরও একটি দ্বিঘাতমূলক ফাংশন পাওয়া যায়।
গুন এবং xorshift দ্বিতীয় প্রয়োগ নিম্নলিখিত উত্পাদন করবে:
অথবা আপনি জিএএইচএসের মতো গ্যালোইস ফিল্ডের গুণগুলি ব্যবহার করতে পারেন , তারা আধুনিক সিপিইউগুলিতে যুক্তিসঙ্গতভাবে দ্রুত হয়ে উঠেছে এবং এক ধাপে উচ্চতর গুণাবলী রয়েছে।
uint64_t const inline gfmul(const uint64_t& i,const uint64_t& j){
__m128i I{};I[0]^=i;
__m128i J{};J[0]^=j;
__m128i M{};M[0]^=0xb000000000000000ull;
__m128i X = _mm_clmulepi64_si128(I,J,0);
__m128i A = _mm_clmulepi64_si128(X,M,0);
__m128i B = _mm_clmulepi64_si128(A,M,0);
return A[0]^A[1]^B[1]^X[0]^X[1];
}
__m128i I = i; //set the lower 64 bits
তবে আমি তা করতে পারি না, তাই আমি ব্যবহার করছি ^=
। 0^1 = 1
সুতরাং কোন চালিত হয় নি। {}
আমার সংকলকটির সাথে আরম্ভের বিষয়ে কখনও অভিযোগ করেনি, এটি সেরা সমাধান নাও হতে পারে তবে আমি এটির সাথে যা চাই তা সবগুলি 0 তে শুরু করা যাতে আমি করতে পারি ^=
বা করতে পারি |=
। আমি ভিত্তিক কোডটি মনে এই ব্লগপোস্টটিকে ডি: যা বিপর্যয়, খুব দরকারী দেয়
৩২-বিটস গুণক পদ্ধতি (খুব দ্রুত) @ ইরাল দেখুন
#define hash32(x) ((x)*2654435761)
#define H_BITS 24 // Hashtable size
#define H_SHIFT (32-H_BITS)
unsigned hashtab[1<<H_BITS]
....
unsigned slot = hash32(x) >> H_SHIFT
32-বিট এবং 64-বিট (ভাল বিতরণ) এ: মর্মুরহশ
এই পৃষ্ঠায় কিছু সাধারণ হ্যাশ ফাংশন তালিকাভুক্ত করা হয় যা সাধারণভাবে শালীনভাবে প্রবণতা রাখে, তবে যে কোনও সাধারণ হ্যাশটিতে প্যাথোলজিকাল কেস রয়েছে যেখানে এটি কার্যকর হয় না।
চিরতরে বিভ্রান্ত হয়ে কিছু হ্যাশ অ্যালগরিদমের উপর একটি সুন্দর ওভারভিউ রয়েছে । আমি বব জেনকিনসের 'এক-সময়ে-সময়ে-সময়ে হ্যাশটি সুপারিশ করব যা দ্রুত হিমস্রোতে পৌঁছে এবং তাই দক্ষ হ্যাশ টেবিল দেখার জন্য ব্যবহার করা যেতে পারে।
উত্তর অনেক কিছুর উপর নির্ভর করে:
আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি SHA-1 ইত্যাদির মতো হ্যাশ ফাংশনগুলির Merkle-Damgard পরিবারের দিকে একবার নজর দিন
আমি মনে করি না যে আমরা বলতে পারি যে কোনও হ্যাশ ফাংশনটি আগে থেকে আপনার ডেটা না জেনে "ভাল"! এবং আপনি এটি দিয়ে কি করতে যাচ্ছেন তা না জেনে।
অজানা তথ্য মাপের জন্য হ্যাশ টেবিলের চেয়ে আরও ভাল ডেটা স্ট্রাকচার রয়েছে (আমি ধরে নিচ্ছি আপনি এখানে একটি হ্যাশ টেবিলের জন্য হ্যাশিং করছেন)। আমি ব্যক্তিগতভাবে একটি হ্যাশ টেবিল ব্যবহার করব যখন আমি জানব যে আমার কাছে একটি "সীমাবদ্ধ" সংখ্যক উপাদান রয়েছে যা সীমিত পরিমাণে মেমরির জন্য সঞ্চয় করা দরকার। আমি চেষ্টা করব এবং আমার ডেটা সম্পর্কে একটি দ্রুত পরিসংখ্যান বিশ্লেষণ করব, আমার হ্যাশ ফাংশন সম্পর্কে চিন্তা শুরু করার আগে এটি কীভাবে বিতরণ করা হয় তা দেখুন।
এলোমেলো হ্যাশ মানগুলির জন্য, কয়েকজন প্রকৌশলী বলেছিলেন যে সোনালি অনুপাতের প্রাইম সংখ্যা (2654435761) একটি খারাপ পছন্দ, আমার পরীক্ষার ফলাফলের সাথে আমি খুঁজে পেয়েছি যে এটি সত্য নয়; পরিবর্তে, 2654435761 হ্যাশ মানগুলি বেশ ভাল বিতরণ করে।
#define MCR_HashTableSize 2^10
unsigned int
Hash_UInt_GRPrimeNumber(unsigned int key)
{
key = key*2654435761 & (MCR_HashTableSize - 1)
return key;
}
হ্যাশ টেবিলের আকারটি অবশ্যই দুটি শক্তির হতে হবে।
আমি পূর্ণসংখ্যার জন্য অনেকগুলি হ্যাশ ফাংশন মূল্যায়নের জন্য একটি পরীক্ষা প্রোগ্রাম লিখেছি, ফলাফলগুলি দেখায় যে জিআরপ্রাইমনিবারটি বেশ ভাল পছন্দ।
আমি চেষ্টা করেছি:
আমার পরীক্ষার ফলাফলের সাথে, আমি দেখতে পেলাম যে গোল্ডেন রেশিয়ো প্রাইম নাম্বারে সর্বদা কম খালি বালতি বা শূন্য শূন্য বালতি এবং সংক্ষিপ্ত সংঘর্ষ শৃঙ্খলার দৈর্ঘ্য রয়েছে।
পূর্ণসংখ্যার জন্য কিছু হ্যাশ ফাংশন ভাল বলে দাবি করা হয়, তবে পরীক্ষার ফলাফলগুলি দেখায় যে মোট_ডেটা_সেন্টারি / মোট_বকেট_নিম্বার = 3 যখন দীর্ঘতম চেইনের দৈর্ঘ্য 10 (সর্বোচ্চ সংঘর্ষের সংখ্যা> 10) এর চেয়ে বড় হয় এবং অনেকগুলি বালতি ম্যাপ করা হয় না (খালি বালতি) ) গোল্ডেন রেশিও প্রাইম নম্বর হ্যাশিংয়ের শূন্য শূন্য বালতি এবং দীর্ঘতম চেইন দৈর্ঘ্যের 3 এর ফলাফলের সাথে তুলনা করে এটি খুব খারাপ।
বিটিডাব্লু, আমার পরীক্ষার ফলাফল সহ, আমি শিফটিং-এক্সওর হ্যাশ ফাংশনগুলির একটি সংস্করণ দেখতে পেয়েছি বেশ ভাল (এটি মাইকের দ্বারা ভাগ করা হয়েছে)।
unsigned int Hash_UInt_M3(unsigned int key)
{
key ^= (key << 13);
key ^= (key >> 17);
key ^= (key << 5);
return key;
}
আমি যখন থেকে এই থ্রেডটি পেয়েছি তখন থেকেই আমি splitmix64
(থমাস মুলারের উত্তরে নির্দেশিত ) ব্যবহার করছি। যাইহোক, আমি সম্প্রতি পেলে ইভেনসেনের rrxmrrxmsx_0 কে হোঁচট খেয়েছি , যা মূল মার্মুরহ্যাশ 3 ফাইনালাইজার এবং এর উত্তরসূরিদের ( splitmix64
এবং অন্যান্য মিশ্রণ) এর চেয়ে মারাত্মকভাবে পরিসংখ্যান বিতরণ পেয়েছিল । সি তে কোড স্নিপেট এখানে রয়েছে:
#include <stdint.h>
static inline uint64_t ror64(uint64_t v, int r) {
return (v >> r) | (v << (64 - r));
}
uint64_t rrxmrrxmsx_0(uint64_t v) {
v ^= ror64(v, 25) ^ ror64(v, 50);
v *= 0xA24BAED4963EE407UL;
v ^= ror64(v, 24) ^ ror64(v, 49);
v *= 0x9FB21C651E98DF25UL;
return v ^ v >> 28;
}
পেলে চূড়ান্ত ধাপে ব্যবহৃত 64-বিট মিক্সারের আরও গভীরতর বিশ্লেষণMurmurHash3
এবং আরও সাম্প্রতিকতম রূপগুলি সরবরাহ করে।