ฟังก์ชันแฮชจำนวนเต็มอะไรดีที่รับคีย์แฮชจำนวนเต็ม


คำตอบ:


48

วิธีการคูณของ Knuth:

hash(i)=i*2654435761 mod 2^32

โดยทั่วไปคุณควรเลือกตัวคูณที่อยู่ในลำดับขนาดแฮชของคุณ (2^32ในตัวอย่าง) และไม่มีปัจจัยร่วมด้วย ด้วยวิธีนี้ฟังก์ชันแฮชจะครอบคลุมพื้นที่แฮชทั้งหมดของคุณอย่างสม่ำเสมอ

แก้ไข: ข้อเสียที่ใหญ่ที่สุดของฟังก์ชันแฮชนี้คือการรักษาความสามารถในการหารดังนั้นหากจำนวนเต็มของคุณหารด้วย 2 หรือ 4 ได้ทั้งหมด (ซึ่งไม่ใช่เรื่องแปลก) แฮชของพวกเขาก็จะมากเกินไป นี่เป็นปัญหาในตารางแฮช - คุณสามารถใช้เพียง 1/2 หรือ 1/4 ของที่เก็บข้อมูลเท่านั้น


38
มันเป็นฟังก์ชันแฮชที่แย่มากแม้ว่าจะติดชื่อดังก็ตาม
Seun Osewa

6
มันไม่ใช่ฟังก์ชันแฮชที่ไม่ดีเลยหากใช้กับขนาดตารางสำคัญ นอกจากนี้ยังมีไว้สำหรับการแฮชแบบปิด หากค่าแฮชไม่กระจายอย่างสม่ำเสมอการแฮชแบบทวีคูณจะช่วยให้มั่นใจได้ว่าการชนกันจากค่าหนึ่งไม่น่าจะ "รบกวน" รายการที่มีค่าแฮชอื่น ๆ
Paolo Bonzini

12
สำหรับคนที่อยากรู้อยากเห็นค่าคงที่นี้ถูกเลือกให้เป็นขนาดแฮช (2 ^ 32) หารด้วย Phi
awdz9nld

8
Paolo: วิธีการของ Knuth นั้น "ไม่ดี" ในแง่ที่ว่ามันไม่ถล่มที่บิตด้านบน
awdz9nld

10
จากการตรวจสอบอย่างใกล้ชิดปรากฎว่า 2654435761 เป็นจำนวนเฉพาะ นั่นอาจเป็นเหตุผลว่าทำไมจึงถูกเลือกมากกว่า 2654435769
karadoc

151

ฉันพบว่าอัลกอริทึมต่อไปนี้มีการแจกแจงทางสถิติที่ดีมาก บิตอินพุตแต่ละบิตมีผลต่อบิตเอาต์พุตแต่ละบิตโดยมีความน่าจะเป็นประมาณ 50% ไม่มีการชนกัน (แต่ละอินพุตส่งผลให้เอาต์พุตต่างกัน) อัลกอริทึมทำงานได้อย่างรวดเร็วยกเว้นว่า CPU ไม่มีหน่วยการคูณจำนวนเต็มในตัว รหัส C สมมติว่าintเป็น 32 บิต (สำหรับ Java แทนที่>>ด้วย>>>และลบunsigned):

unsigned int hash(unsigned int x) {
    x = ((x >> 16) ^ x) * 0x45d9f3b;
    x = ((x >> 16) ^ x) * 0x45d9f3b;
    x = (x >> 16) ^ x;
    return x;
}

ตัวเลขมหัศจรรย์คำนวณโดยใช้โปรแกรมทดสอบแบบมัลติเธรดพิเศษที่ทำงานเป็นเวลาหลายชั่วโมงซึ่งคำนวณเอฟเฟกต์หิมะถล่ม (จำนวนบิตเอาต์พุตที่เปลี่ยนแปลงหากบิตอินพุตเดียวมีการเปลี่ยนแปลงควรเฉลี่ยเกือบ 16) ความเป็นอิสระของ การเปลี่ยนแปลงบิตเอาต์พุต (บิตเอาต์พุตไม่ควรขึ้นอยู่กับกันและกัน) และความน่าจะเป็นของการเปลี่ยนแปลงในแต่ละบิตเอาต์พุตหากบิตอินพุตมีการเปลี่ยนแปลง ค่าที่คำนวณได้ดีกว่า finalizer 32 บิตใช้โดย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 บิตฉันขอแนะนำให้ใช้สิ่งต่อไปนี้แม้ว่าจะคิดว่าอาจไม่เร็วที่สุด อันนี้อ้างอิงจากSplitmix64ซึ่งดูเหมือนจะมาจากบทความบล็อกBetter Bit Mixing (ผสม 13)

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;
}

สำหรับ Java, การใช้งาน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;
}

อัปเดต: คุณอาจต้องการดูโครงการHash Function Prospectorซึ่งมีการระบุค่าคงที่อื่น ๆ (อาจดีกว่า)


2
สองบรรทัดแรกเหมือนกันเป๊ะ! มีการพิมพ์ผิดไหม
Kshitij Banerjee

3
ไม่นี่ไม่ใช่การพิมพ์ผิดบรรทัดที่สองจะผสมบิตต่อไป การใช้การคูณเพียงครั้งเดียวนั้นไม่ดีเท่า
Thomas Mueller

3
ฉันเปลี่ยนเลขวิเศษเพราะตามกรณีทดสอบฉันเขียนค่า 0x45d9f3b ให้ความสับสนและการแพร่กระจายที่ดีขึ้นโดยเฉพาะอย่างยิ่งว่าหากบิตเอาต์พุตหนึ่งบิตเปลี่ยนไปบิตเอาต์พุตอื่น ๆ จะเปลี่ยนไปโดยมีความน่าจะเป็นเท่ากัน (นอกเหนือจากบิตเอาต์พุตทั้งหมดจะเปลี่ยนไปด้วย ความน่าจะเป็นเหมือนกันหากบิตอินพุตเปลี่ยนแปลง) คุณวัด 0x3335b369 ได้ผลดีกว่าสำหรับคุณอย่างไร int 32 บิตสำหรับคุณหรือไม่?
Thomas Mueller

3
ฉันกำลังค้นหาฟังก์ชันแฮชที่ดีสำหรับ 64 บิตที่ไม่ได้ลงนาม int เป็น 32 บิต int ที่ไม่ได้ลงนาม สำหรับกรณีนั้นเลขวิเศษข้างบนจะเหมือนกันหรือไม่? ฉันเลื่อน 32 บิตแทนที่จะเป็น 16 บิต
alessandro

3
ฉันเชื่อว่าในกรณีนี้ปัจจัยที่ใหญ่กว่าจะดีกว่า แต่คุณจะต้องทำการทดสอบบางอย่าง หรือ (นี่คือสิ่งที่ฉันทำ) ใช้ก่อนx = ((x >> 32) ^ x)แล้วใช้การคูณ 32 บิตด้านบน ฉันไม่แน่ใจว่าอะไรดีขึ้น คุณอาจต้องการดูFinalizer 64 บิตสำหรับ Murmur3
Thomas Mueller

29

ขึ้นอยู่กับวิธีการกระจายข้อมูลของคุณ สำหรับเคาน์เตอร์ธรรมดาฟังก์ชันที่ง่ายที่สุด

f(i) = i

จะดี (ฉันสงสัยว่าดีที่สุด แต่ฉันไม่สามารถพิสูจน์ได้)


3
ปัญหาของเรื่องนี้คือเป็นเรื่องปกติที่จะมีจำนวนเต็มจำนวนมากที่หารด้วยปัจจัยร่วมกันได้ (ที่อยู่หน่วยความจำจัดแนวคำเป็นต้น) ตอนนี้ถ้าตารางแฮชของคุณหารด้วยปัจจัยเดียวกันคุณจะใช้เพียงครึ่งหนึ่ง (หรือ 1/4, 1/8 ฯลฯ ) ที่เก็บข้อมูล
Rafał Dowgird

8
@Rafal: นั่นคือเหตุผลที่คำตอบระบุว่า "สำหรับตัวนับธรรมดา" และ "ขึ้นอยู่กับวิธีการกระจายข้อมูลของคุณ"
erikkallen

5
นั่นคือการใช้งานโดย Sun ของวิธีการ hashCode () ใน java.lang.Integer grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
Juande Carrion

5
@JuandeCarrion นั่นทำให้เข้าใจผิดเพราะนั่นไม่ใช่แฮชที่กำลังใช้อยู่ หลังจากที่ย้ายไปอยู่กับการใช้อำนาจของสองขนาดโต๊ะ, Java rehashes กัญชากลับมาจากทุก.hashCode()ดูที่นี่
Esailija

8
ฟังก์ชันระบุตัวตนค่อนข้างไร้ประโยชน์เนื่องจากแฮชในแอปพลิเคชันที่ใช้งานได้จริงจำนวนมากเนื่องจากคุณสมบัติการกระจาย (หรือไม่มี) เว้นแต่แน่นอนว่า
โลคัล

12

ฟังก์ชันแฮชที่รวดเร็วและดีสามารถประกอบด้วยการเรียงสับเปลี่ยนอย่างรวดเร็วที่มีคุณสมบัติน้อยกว่าเช่น

  • การคูณด้วยจำนวนเต็มไม่สม่ำเสมอ
  • การหมุนแบบไบนารี
  • xorshift

เพื่อให้ได้ฟังก์ชันการแฮชที่มีคุณสมบัติที่เหนือกว่าเช่นที่แสดงด้วยPCGสำหรับการสร้างตัวเลขแบบสุ่ม

อันที่จริงแล้วนี่คือสูตร rrxmrrxmsx_0 และแฮชบ่นกำลังใช้โดยไม่รู้ตัวหรือไม่รู้

ฉันเองพบ

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. เรียงซ้อนให้มากที่สุดเท่าที่จะเป็นไปได้กล่าวคือแต่ละบิตอินพุตควรพลิกทุกบิตเอาต์พุตด้วยความน่าจะเป็น 0.5

ก่อนอื่นเรามาดูฟังก์ชันเอกลักษณ์ เป็นไปตาม 1. แต่ไม่ใช่ 2. :

ฟังก์ชันเอกลักษณ์

บิตอินพุต n กำหนดบิตเอาต์พุต n โดยมีความสัมพันธ์ 100% (สีแดง) และไม่มีอื่น ๆ ดังนั้นจึงเป็นสีน้ำเงินทำให้มีเส้นสีแดงที่สมบูรณ์แบบ

xorshift (n, 32) ไม่ดีกว่ามากโดยให้ผลครึ่งบรรทัด ยังคงเป็นที่น่าพอใจ 1. เนื่องจากสามารถกลับด้านได้ด้วยแอปพลิเคชันที่สอง

xorshift

การคูณด้วยจำนวนเต็มที่ไม่ได้ลงนามจะดีกว่ามากเรียงซ้อนกันแรงกว่าและพลิกบิตเอาต์พุตมากขึ้นโดยมีความน่าจะเป็น 0.5 ซึ่งเป็นสิ่งที่คุณต้องการเป็นสีเขียว เป็นไปตาม 1. สำหรับจำนวนเต็มที่ไม่เท่ากันแต่ละตัวจะมีผกผันการคูณ

knuth

การรวมทั้งสองอย่างให้ผลลัพธ์ต่อไปนี้ยังคงเป็นที่น่าพอใจ 1. เนื่องจากองค์ประกอบของฟังก์ชัน bijective สองฟังก์ชันจะให้ฟังก์ชัน bijective อื่น

knuth • xorshift

การประยุกต์ใช้การคูณและ xorshift ครั้งที่สองจะให้ผลดังนี้:

แฮชที่เสนอ

หรือคุณสามารถใช้การคูณฟิลด์ Galois เช่นGHashมันกลายเป็นซีพียูที่รวดเร็วพอสมควรและมีคุณสมบัติที่เหนือกว่าในขั้นตอนเดียว

   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];                                              
   }

gfmul: รหัสดูเหมือนจะเป็นรหัสหลอกเนื่องจาก afaik คุณไม่สามารถใช้วงเล็บกับ __m128i ได้ ยังคงน่าสนใจมาก บรรทัดแรกจะเขียนว่า "take an unitialized __m128i (I) และ xor it with (parameter) i. ฉันควรอ่านค่านี้เมื่อเริ่มต้น I ด้วย 0 และ xor ด้วย i หรือไม่ถ้าเป็นเช่นนั้นจะเหมือนกับ load I with i และดำเนินการไม่ (การดำเนินการ) บน I?
ม.ค.

@Jan สิ่งที่ฉันต้องการจะทำคือการแต่ที่ผมไม่สามารถดังนั้นฉันใช้__m128i I = i; //set the lower 64 bits ดังนั้นจึงไม่ไม่ถูกบุกรุก เกี่ยวกับ initialisation กับคอมไพเลอร์ของฉันไม่เคยบ่นก็ไม่อาจจะเป็นทางออกที่ดีที่สุด แต่สิ่งที่ฉันต้องการมีที่อยู่ Initialise ทั้งหมดของมันให้เป็น 0 ดังนั้นฉันสามารถทำได้หรือ ฉันคิดว่าฉันใช้รหัสนั้นในบล็อกโพสต์นี้ซึ่งให้การผกผันที่มีประโยชน์มาก: D^=0^1 = 1{}^=|=
Wolfgang Brehm

7
  • วิธีการคูณ 32 บิต (เร็วมาก) ดูที่ @rafal

    #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 บิต (การกระจายที่ดี) ที่: MurmurHash

  • ฟังก์ชัน Integer Hash


3

มีภาพรวมที่ดีกว่าขั้นตอนวิธีกัญชาบางEternally Confuzzled ฉันขอแนะนำแฮชแบบครั้งละครั้งของ Bob Jenkins ซึ่งสามารถเข้าถึงได้อย่างรวดเร็วดังนั้นจึงสามารถใช้สำหรับการค้นหาตารางแฮชที่มีประสิทธิภาพ


4
เป็นบทความที่ดี แต่เน้นที่การแฮชคีย์สตริงไม่ใช่จำนวนเต็ม
Adrian Mouat

เพื่อความชัดเจนแม้ว่าวิธีการในบทความจะใช้ได้กับจำนวนเต็ม (หรือสามารถปรับให้เข้ากับ) แต่ฉันคิดว่ามีอัลกอริทึมที่มีประสิทธิภาพมากกว่าสำหรับจำนวนเต็ม
Adrian Mouat

2

คำตอบขึ้นอยู่กับหลายสิ่งเช่น:

  • คุณตั้งใจจะจ้างงานที่ไหน
  • คุณกำลังพยายามทำอะไรกับแฮช?
  • คุณต้องการฟังก์ชันแฮชที่ปลอดภัยโดยเข้ารหัสหรือไม่?

ฉันขอแนะนำให้คุณดูฟังก์ชันแฮชตระกูลMerkle-Damgardเช่น SHA-1 เป็นต้น


1

ฉันไม่คิดว่าเราจะสามารถพูดได้ว่าฟังก์ชันแฮชนั้น "ดี" โดยไม่รู้ข้อมูลของคุณล่วงหน้า! และไม่รู้ว่าคุณกำลังจะทำอะไรกับมัน

มีโครงสร้างข้อมูลที่ดีกว่าตารางแฮชสำหรับขนาดข้อมูลที่ไม่รู้จัก (ฉันสมมติว่าคุณกำลังทำแฮชสำหรับตารางแฮชที่นี่) ฉันจะใช้ตารางแฮชเป็นการส่วนตัวเมื่อฉันรู้ว่าฉันมีองค์ประกอบ "จำกัด " จำนวนหนึ่งที่จำเป็นต้องจัดเก็บไว้ในหน่วยความจำจำนวน จำกัด ฉันจะลองทำการวิเคราะห์ทางสถิติอย่างรวดเร็วเกี่ยวกับข้อมูลของฉันดูว่ามีการกระจายอย่างไร ฯลฯ ก่อนที่ฉันจะเริ่มคิดถึงฟังก์ชันแฮชของฉัน


1

สำหรับค่าแฮชแบบสุ่มวิศวกรบางคนกล่าวว่าจำนวนเฉพาะของอัตราส่วนทองคำ (2654435761) เป็นตัวเลือกที่ไม่ดีด้วยผลการทดสอบของฉันฉันพบว่ามันไม่เป็นความจริง แทน 2654435761 กระจายค่าแฮชค่อนข้างดี

#define MCR_HashTableSize 2^10

unsigned int
Hash_UInt_GRPrimeNumber(unsigned int key)
{
  key = key*2654435761 & (MCR_HashTableSize - 1)
  return key;
}

ขนาดตารางแฮชต้องมีกำลังสอง

ฉันได้เขียนโปรแกรมทดสอบเพื่อประเมินฟังก์ชันแฮชสำหรับจำนวนเต็มผลปรากฏว่า GRPrimeNumber เป็นตัวเลือกที่ดีทีเดียว

ฉันเหนื่อย:

  1. total_data_entry_number / total_bucket_number = 2, 3, 4; โดยที่ total_bucket_number = ขนาดตารางแฮช;
  2. แมปโดเมนค่าแฮชลงในโดเมนดัชนีถัง นั่นคือแปลงค่าแฮชเป็นดัชนีถังโดย Logical And Operation with (hash_table_size - 1) ดังที่แสดงใน Hash_UInt_GRPrimeNumber ();
  3. คำนวณจำนวนการชนกันของแต่ละถัง
  4. บันทึกที่เก็บข้อมูลที่ไม่ได้รับการแมปนั่นคือที่เก็บข้อมูลเปล่า
  5. ค้นหาจำนวนการชนกันสูงสุดของที่เก็บข้อมูลทั้งหมด นั่นคือความยาวโซ่ที่ยาวที่สุด

จากผลการทดสอบของฉันฉันพบว่า Golden Ratio Prime Number มีที่เก็บข้อมูลที่ว่างน้อยกว่าหรือที่เก็บข้อมูลว่างเป็นศูนย์เสมอ

ฟังก์ชันแฮชบางฟังก์ชันสำหรับจำนวนเต็มถูกอ้างว่าดี แต่ผลการทดสอบแสดงให้เห็นว่าเมื่อ total_data_entry / total_bucket_number = 3 ความยาวโซ่ที่ยาวที่สุดจะมากกว่า 10 (จำนวนการชนสูงสุด> 10) และที่เก็บข้อมูลจำนวนมากจะไม่ถูกแมป (ที่เก็บข้อมูลว่าง ) ซึ่งแย่มากเมื่อเทียบกับผลของถังเปล่าเป็นศูนย์และความยาวโซ่ที่ยาวที่สุด 3 โดย Golden Ratio Prime Number Hashing

BTW จากผลการทดสอบของฉันฉันพบว่าฟังก์ชันแฮช shifting-xor เวอร์ชันหนึ่งค่อนข้างดี (แชร์โดย mikera)

unsigned int Hash_UInt_M3(unsigned int key)
{
  key ^= (key << 13);
  key ^= (key >> 17);    
  key ^= (key << 5); 
  return key;
}

2
แต่ทำไมไม่เปลี่ยนผลิตภัณฑ์ให้ถูกต้องเพื่อให้คุณเก็บบิตที่ผสมมากที่สุดไว้ นั่นคือวิธีที่ควรจะได้ผล
harold

1
@harold มีการเลือกจำนวนเฉพาะของอัตราส่วนทองคำอย่างระมัดระวังแม้ว่าฉันคิดว่ามันจะไม่สร้างความแตกต่าง แต่ฉันจะทดสอบดูว่ามันดีกว่ามากหรือไม่ด้วย "บิตที่ผสมกันมากที่สุด" ในขณะที่ประเด็นของฉันก็คือ "มันไม่ใช่ทางเลือกที่ดี" ไม่เป็นความจริงตามที่ผลการทดสอบแสดงเพียงแค่จับส่วนล่างของบิตก็เพียงพอแล้วและดีกว่าฟังก์ชันแฮชมากมาย
Chen-ChungChia

(2654435761, 4295203489) เป็นอัตราส่วนทองคำของไพรม์
Chen-ChungChia

(1640565991, 2654435761) เป็นอัตราส่วนทองคำของไพรม์เช่นกัน
Chen-ChungChia

@harold การขยับผลิตภัณฑ์ให้ถูกต้องจะแย่ลงแม้ว่าจะขยับไปทางขวาทีละ 1 ตำแหน่ง (หารด้วย 2) แต่ก็ยังแย่ลง (แม้ว่าจะยังคงเป็นถังเปล่าเป็นศูนย์ แต่ความยาวโซ่ที่ยาวที่สุดจะใหญ่กว่า) การเลื่อนตำแหน่งไปทางขวามากขึ้นผลลัพธ์จะแย่ลงมากขึ้น ทำไม? ฉันคิดว่าเหตุผลคือ: การเปลี่ยนผลิตภัณฑ์ให้ถูกต้องทำให้ค่าแฮชมากขึ้นไม่ให้เป็น coprime เพียงแค่ฉันเดาเหตุผลที่แท้จริงเกี่ยวข้องกับทฤษฎีจำนวน
Chen-ChungChia

1

ฉันใช้splitmix64(ชี้ในคำตอบของ Thomas Mueller ) ตั้งแต่ฉันพบหัวข้อนี้ อย่างไรก็ตามเมื่อเร็ว ๆ นี้ฉันได้สะดุดกับrrxmrrxmsx_0ของ Pelle Evensen ซึ่งให้การกระจายทางสถิติที่ดีขึ้นอย่างมากเมื่อเทียบกับโปรแกรมสรุปขั้นสุดท้าย MurmurHash3 และตัวต่อ ( splitmix64และส่วนผสมอื่น ๆ ) นี่คือข้อมูลโค้ดใน C:

#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;
}

นอกจากนี้ Pelle ยังมีการวิเคราะห์เชิงลึกของมิกเซอร์ 64 บิตที่ใช้ในขั้นตอนสุดท้ายMurmurHash3และตัวแปรล่าสุด


2
ฟังก์ชั่นนี้ไม่เกี่ยวกับอคติ สำหรับ v ทั้งหมดโดยที่ v = ror (v, 25) คือทั้งหมด 0 และทั้งหมด 1 จะให้ผลลัพธ์เดียวกันในสองตำแหน่ง สำหรับค่าทั้งหมด v = ror64 (v, 24) ^ ror64 (v, 49) ซึ่งมากกว่าอย่างน้อยสองค่าและเหมือนกันกับ v = ror (v, 28) ให้ผลอีก 2 ^ 4 รวมประมาณ 22 การชนที่ไม่จำเป็น . แอพพลิเคชั่น Splitmix สองแอพอาจจะดีพอ ๆ กันและเร็วพอ ๆ กัน แต่ก็ยังกลับหัวไม่ได้และไม่มีการชนกัน
Wolfgang Brehm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.