कैंटर पेयरिंग फंक्शन वास्तव में बेहतर लोगों में से एक है, जो इसके सरल, तेज और अंतरिक्ष कुशल पर विचार कर रहा है, लेकिन मैथ्यू स्ज़्ज़िक द्वारा वुल्फराम में कुछ और भी बेहतर प्रकाशित किया गया है । कैंटर पेयरिंग फ़ंक्शन (अपेक्षाकृत) की सीमा यह है कि एन्कोडेड परिणामों की सीमा हमेशा 2N
बिट पूर्णांक की सीमा के भीतर नहीं रहती है यदि इनपुट दो N
बिट पूर्णांक होते हैं। यही है, अगर मेरे इनपुट दो 16
बिट पूर्णांक हैं 0 to 2^16 -1
, तो 2^16 * (2^16 -1)
इनपुट के संयोजन संभव हैं, इसलिए स्पष्ट पिजनहोल सिद्धांत द्वारा , हमें कम से कम आकार का एक आउटपुट चाहिए 2^16 * (2^16 -1)
, जो कि समान है 2^32 - 2^16
, या दूसरे शब्दों में, का एक नक्शा32
बिट संख्या आदर्श रूप से संभव होनी चाहिए। यह प्रोग्रामिंग की दुनिया में बहुत कम व्यावहारिक महत्व नहीं हो सकता है।
कैंटर बाँधने का कार्य :
(a + b) * (a + b + 1) / 2 + a; where a, b >= 0
दो अधिकतम 16 बिट पूर्णांक (65535, 65535) के लिए मैपिंग 8589803520 होगी जो कि आप देखते हैं कि 32 बिट्स में फिट नहीं किया जा सकता है।
दर्ज करें Szudzik का कार्य :
a >= b ? a * a + a + b : a + b * b; where a, b >= 0
(65535, 65535) मानचित्रण अब 4294967295 होगा, जैसा कि आप देख रहे हैं कि 32 बिट (0 से 2 ^ 32 -1) पूर्णांक है। यह वह जगह है जहां यह समाधान आदर्श है, यह बस उस स्थान में हर एक बिंदु का उपयोग करता है, इसलिए कुछ भी अधिक कुशल स्थान प्राप्त नहीं कर सकता है।
अब इस तथ्य पर विचार करते हुए कि हम आम तौर पर भाषाओं / रूपरेखाओं में विभिन्न आकारों की संख्याओं के हस्ताक्षरित कार्यान्वयन के साथ सौदा करते हैं, आइए signed 16
बिट बिटर्स से लेकर विचार करें -(2^15) to 2^15 -1
(बाद में हम देखेंगे कि हस्ताक्षरित सीमा पर भी कहां तक विस्तार करना है)। कब से a
और b
सकारात्मक होना है, वे किस सीमा तक हैं 0 to 2^15 - 1
।
कैंटर बाँधने का कार्य :
दो अधिकतम 16 बिट हस्ताक्षरित पूर्णांक (32767, 32767) के लिए मैपिंग 2147418112 होगी जो हस्ताक्षरित 32 बिट पूर्णांक के लिए अधिकतम मूल्य से कुछ ही कम है।
अब ज़ुदज़िक का कार्य :
(32767, 32767) => 1073741823, बहुत छोटा ।।
चलो नकारात्मक पूर्णांक के लिए खाता है। यह मेरे द्वारा ज्ञात मूल प्रश्न से परे है, लेकिन भविष्य के आगंतुकों की मदद करने के लिए विस्तृत है।
कैंटर बाँधने का कार्य :
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
(A + B) * (A + B + 1) / 2 + A;
(-32768, -32768) => 8589803520 जो कि Int64 है। 16 बिट इनपुट के लिए 64 बिट आउटपुट इतना अनपेक्षित हो सकता है !!
ज़ुदज़िक का कार्य :
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
A >= B ? A * A + A + B : A + B * B;
(-32768, -32768) => 4294967295 जो अहस्ताक्षरित सीमा के लिए 32 बिट या हस्ताक्षरित सीमा के लिए 64 बिट है, लेकिन फिर भी बेहतर है।
अब यह सब जबकि आउटपुट हमेशा सकारात्मक रहा है। हस्ताक्षरित दुनिया में, यह और भी अधिक स्थान की बचत होगी यदि हम आधे आउटपुट को नकारात्मक अक्ष पर स्थानांतरित कर सकते हैं । आप इसे Szudzik के लिए इस तरह कर सकते हैं:
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
C = (A >= B ? A * A + A + B : A + B * B) / 2;
a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
(-32768, 32767) => -2147483648
(32767, -32768) => -2147450880
(0, 0) => 0
(32767, 32767) => 2147418112
(-32768, -32768) => 2147483647
मैं क्या करता हूं: 2
इनपुट का एक भार लागू करने और फ़ंक्शन के माध्यम से जाने के बाद, मैं फिर से ouput को दो से विभाजित करता हूं और उनमें से कुछ को गुणा करके नकारात्मक अक्ष पर ले जाता हूं -1
।
परिणाम देखें, किसी हस्ताक्षरित 16
बिट संख्या की सीमा में किसी भी इनपुट के लिए , आउटपुट एक हस्ताक्षरित 32
बिट पूर्णांक की सीमा के भीतर है जो शांत है। मुझे यकीन नहीं है कि कैंटर पेयरिंग फंक्शन के लिए उसी तरह से जाना जा सकता है, लेकिन जितना संभव हो उतना कुशल नहीं था। इसके अलावा, कैंटर पेयरिंग फंक्शन में शामिल होने वाले अधिक कैलकुलेशन का अर्थ है, इसका धीमा होना ।
यहाँ एक C # कार्यान्वयन है।
public static long PerfectlyHashThem(int a, int b)
{
var A = (ulong)(a >= 0 ? 2 * (long)a : -2 * (long)a - 1);
var B = (ulong)(b >= 0 ? 2 * (long)b : -2 * (long)b - 1);
var C = (long)((A >= B ? A * A + A + B : A + B * B) / 2);
return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}
public static int PerfectlyHashThem(short a, short b)
{
var A = (uint)(a >= 0 ? 2 * a : -2 * a - 1);
var B = (uint)(b >= 0 ? 2 * b : -2 * b - 1);
var C = (int)((A >= B ? A * A + A + B : A + B * B) / 2);
return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}
चूंकि मध्यवर्ती गणनाएं 2N
हस्ताक्षरित पूर्णांक की सीमाओं को पार कर सकती हैं , इसलिए मैंने 4N
पूर्णांक प्रकार (अंतिम विभाजन द्वारा 2
परिणाम वापस लाता है 2N
) का उपयोग किया है।
वैकल्पिक समाधान पर मैंने जो लिंक प्रदान किया है वह अंतरिक्ष में हर एक बिंदु का उपयोग करते हुए फ़ंक्शन के एक ग्राफ को दर्शाता है। यह देखने के लिए आश्चर्यजनक है कि आप विशिष्ट रूप से एक ही संख्या में निर्देशांक की एक जोड़ी को उलट सकते हैं! नंबरों की जादुई दुनिया !!