कब हैथ (n) == n पायथन में?


100

मैं पायथन के हैश फंक्शन के साथ खेल रहा हूं । छोटे पूर्णांकों के लिए, यह hash(n) == nहमेशा दिखाई देता है । हालाँकि यह बड़ी संख्या में विस्तारित नहीं होता है:

>>> hash(2**100) == 2**100
False

मुझे आश्चर्य नहीं है, मुझे समझ में हैश मूल्यों की एक सीमित सीमा लेता है। वह सीमा क्या है?

मैंने सबसे छोटी संख्या खोजने के लिए बाइनरी खोज का उपयोग करने की कोशिश कीhash(n) != n

>>> import codejamhelpers # pip install codejamhelpers
>>> help(codejamhelpers.binary_search)
Help on function binary_search in module codejamhelpers.binary_search:

binary_search(f, t)
    Given an increasing function :math:`f`, find the greatest non-negative integer :math:`n` such that :math:`f(n) \le t`. If :math:`f(n) > t` for all :math:`n \ge 0`, return None.

>>> f = lambda n: int(hash(n) != n)
>>> n = codejamhelpers.binary_search(f, 0)
>>> hash(n)
2305843009213693950
>>> hash(n+1)
0

2305843009213693951 में क्या खास है? मैंने ध्यान दिया कि यह इससे कम हैsys.maxsize == 9223372036854775807

संपादित करें: मैं Python 3 का उपयोग कर रहा हूं। मैंने Python 2 पर एक ही बाइनरी खोज को चलाया और 2147483648 पर एक अलग परिणाम प्राप्त किया, जो मैंने नोट किया है sys.maxint+1

मैंने [hash(random.random()) for i in range(10**6)]हैश फ़ंक्शन की सीमा का अनुमान लगाने के लिए भी खेला । अधिकतम लगातार ऊपर n से नीचे है। मिनट की तुलना में, ऐसा लगता है कि पायथन 3 का हैश हमेशा सकारात्मक रूप से मूल्यवान है, जबकि पायथन 2 का हैश नकारात्मक मान ले सकता है।


9
क्या आपने नंबर की बाइनरी प्रतिनिधित्व की जांच की है?
जॉन ड्वोरक

3
'0b111111111111111111111111111111111111111111111111111111111111111' जिज्ञासु! तो n+1 == 2**61-1
कर्नल पैनिक

2
सिस्टम पर निर्भर होने लगता है। मेरे अजगर के साथ, हैश nपूरे 64 बिट इंट रेंज के लिए है।
डैनियल

1
हैश मूल्य के घोषित उद्देश्य पर ध्यान दें: वे शब्दकोश खोज के दौरान शब्दकोश कुंजियों की जल्दी तुलना करने के लिए उपयोग किए जाते हैं। दूसरे शब्दों में, कार्यान्वयन-परिभाषित, और कई मूल्यों से छोटे होने के आधार पर, जिनके पास हैश मूल्य हो सकते हैं, उचित इनपुट स्थानों में भी बहुत अच्छी तरह से टकराव हो सकते हैं।
बजे एक CVn

2
उम, है न 2147483647के बराबर sys.maxint(नहीं sys.maxint+1), और यदि 'एन = 0b1111111111111111111111111111111111111111111111111111111111111' तो नहीं है n+1 == 2**61या n == 2**61-1(नहीं n+1 == 2**61-1)?
फोग

जवाबों:


73

pyhash.cफ़ाइल में अजगर प्रलेखन के आधार पर :

संख्यात्मक प्रकारों के लिए, संख्या x का हैश x मॉडुलो प्राइम की कमी पर आधारित है P = 2**_PyHASH_BITS - 1। इसे इसलिए डिज़ाइन किया गया है कि hash(x) == hash(y)जब भी x और y संख्यात्मक रूप से बराबर हों, भले ही x और y अलग-अलग प्रकार के हों।

तो 64/32 बिट मशीन के लिए, कमी 2 _PHHASH_BITS - 1 होगी, लेकिन क्या है _PyHASH_BITS?

आप इसे pyhash.hहेडर फ़ाइल में पा सकते हैं जिसे 64 बिट मशीन के लिए 61 के रूप में परिभाषित किया गया है (आप pyconfig.hफ़ाइल में अधिक विवरण पढ़ सकते हैं )।

#if SIZEOF_VOID_P >= 8
#  define _PyHASH_BITS 61
#else
#  define _PyHASH_BITS 31
#endif

तो सबसे पहले यह मेरे 64 बिट लिनक्स प्लेटफॉर्म में उदाहरण के लिए आपके प्लेटफॉर्म पर आधारित है, कमी 2 61 -1 है, जो है 2305843009213693951:

>>> 2**61 - 1
2305843009213693951

इसके अलावा आप math.frexpमंटिसा और sys.maxint64 बिट मशीन के लिए एक्सपोनेंट प्राप्त करने के लिए उपयोग कर सकते हैं , यह दर्शाता है कि अधिकतम इंट 2 2 63 है

>>> import math
>>> math.frexp(sys.maxint)
(0.5, 64)

और आप एक साधारण परीक्षण द्वारा अंतर देख सकते हैं:

>>> hash(2**62) == 2**62
True
>>> hash(2**63) == 2**63
False

अजगर हैशिंग एल्गोरिथ्म https://github.com/python/cpython/blob/master/Python/pyhash.c#L34 के बारे में पूरा प्रलेखन पढ़ें

जैसा कि टिप्पणी में उल्लेख किया गया है आप sys.hash_info(अजगर 3.X में) का उपयोग कर सकते हैं जो आपको कंप्यूटिंग हैश के लिए उपयोग किए जाने वाले मापदंडों का एक संरचनात्मक अनुक्रम देगा।

>>> sys.hash_info
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003, algorithm='siphash24', hash_bits=64, seed_bits=128, cutoff=0)
>>> 

पूर्ववर्ती लाइनों में मेरे द्वारा वर्णित मापांक के साथ, आप infनिम्न के रूप में मूल्य भी प्राप्त कर सकते हैं :

>>> hash(float('inf'))
314159
>>> sys.hash_info.inf
314159

3
sys.hash_infoपूर्णता के लिए, इसका उल्लेख करना अच्छा होगा ।
मार्क डिकिंसन

78

2305843009213693951है 2^61 - 1। यह सबसे बड़ा Mersenne प्राइम है जो 64 बिट्स में फिट होता है।

यदि आपको वैल्यू मॉड को कुछ संख्या में ले कर हैश बनाना है, तो एक बड़ा मेर्सन प्राइम एक अच्छा विकल्प है - यह गणना करना आसान है और संभावनाओं का एक समान वितरण सुनिश्चित करता है। (हालांकि मैं व्यक्तिगत रूप से इस तरह से हैश नहीं बनाऊंगा)

यह अस्थायी बिंदु संख्याओं के लिए मापांक की गणना करने के लिए विशेष रूप से सुविधाजनक है। उनके पास एक घातीय घटक है जो पूरे संख्या को गुणा करता है 2^x। चूंकि 2^61 = 1 mod 2^61-1, आपको केवल विचार करने की आवश्यकता है (exponent) mod 61

देखें: https://en.wikipedia.org/wiki/Mersenne_prime


8
आप कहते हैं कि आप कभी इस तरह हैश नहीं करेंगे। क्या आपके पास वैकल्पिक सुझाव हैं कि यह किस तरह से किया जा सकता है जो कि किलों, फ़्लोट्स, डेसीमल, फ़्रैक्शन्स के लिए गणना करने के लिए उचित रूप से कुशल बनाता है और यह सुनिश्चित करता है कि सभी प्रकार की x == yगारंटी देता है hash(x) == hash(y)? (जैसे संख्याएँ Decimal('1e99999999')विशेष रूप से समस्याग्रस्त हैं, उदाहरण के लिए: आप उन्हें हैशिंग से पहले संबंधित पूर्णांक तक विस्तारित नहीं करना चाहते।)
मार्क डिकिन्सन

@MarkDickinson मुझे संदेह है कि वह इस सरल बिजली के तेज हैश, और क्रिप्टोग्राफिक हैश के बीच एक अंतर खींचने की कोशिश कर रहा है जो आउटपुट को यादृच्छिक बनाने के बारे में परवाह करता है।
माइक ऑन्सवर्थ

4
@MarkDickinson मॉडुलस एक अच्छी शुरुआत है, लेकिन मैं तब इसे कुछ और मिलाऊंगा, विशेष रूप से कुछ उच्च बिट्स को कम में मिलाकर। यह 2 की शक्तियों से विभाज्य पूर्णांक के अनुक्रम को देखना असामान्य नहीं है। यह क्षमता के साथ हैश टेबल को देखने के लिए भी असामान्य नहीं है। 2 की शक्तियां हैं। उदाहरण के लिए, यदि आपके पास पूर्णांकों का अनुक्रम है जो 16 से विभाज्य हैं, आप उन्हें एक हाशप में कुंजियों के रूप में उपयोग करते हैं, आप केवल 1/16 बाल्टियों का उपयोग करेंगे (कम से कम मैं जिस स्रोत को देख रहा हूं उसके संस्करण में)! मुझे लगता है कि इन प्रोब्लम से बचने के लिए हैश को कम से कम थोड़ा बेतरतीब-सा दिखना चाहिए
मैट

हां, बिट-मिक्सिंग स्टाइल हैश गणित से प्रेरित लोगों से कहीं बेहतर है। बिट-मिक्सिंग निर्देश इतने सस्ते हैं कि आप एक ही कीमत पर कई हो सकते हैं। इसके अलावा, वास्तविक विश्व डेटा में ऐसे पैटर्न नहीं हैं जो बिट मिश्रण के साथ अच्छी तरह से काम नहीं करते हैं। लेकिन ऐसे पैटर्न हैं जो मापांक के लिए भयानक हैं।
यूएसआर

9
@usr: उस के लिए हैश काम आवश्यकता: ज़रूर, लेकिन थोड़ा-मिश्रण हैश यहाँ अव्यवहार्य है int, float, Decimalऔर Fractionवस्तुओं और उस x == yका अर्थ है hash(x) == hash(y)यहां तक कि जब xऔर yविभिन्न प्रकार कुछ नहीं बल्कि गंभीर की कमी लगाता है। यदि यह पूर्णांक के लिए हैश फ़ंक्शन लिखने की बात थी, तो अन्य प्रकारों की चिंता किए बिना, यह पूरी तरह से अलग मामला होगा।
मार्क डिकिंसन

9

हैश फंक्शन सादा int देता है जिसका अर्थ है कि लौटाया गया मान इससे अधिक -sys.maxintऔर कम है sys.maxint, जिसका अर्थ है कि यदि आप sys.maxint + xइसे पास करते हैं तो परिणाम होगा -sys.maxint + (x - 2)

hash(sys.maxint + 1) == sys.maxint + 1 # False
hash(sys.maxint + 1) == - sys.maxint -1 # True
hash(sys.maxint + sys.maxint) == -sys.maxint + sys.maxint - 2 # True

इस बीच 2**200की nतुलना में कई गुना अधिक है sys.maxint- मेरा अनुमान है कि हैश उस -sys.maxint..+sys.maxintसमय तक रेंज n पर जाएगा जब तक कि उस श्रेणी में सादे पूर्णांक पर नहीं रुकता, जैसे ऊपर कोड स्निपेट में।

तो आमतौर पर, किसी भी n <= sys.maxint के लिए :

hash(sys.maxint*n) == -sys.maxint*(n%2) +  2*(n%2)*sys.maxint - n/2 - (n + 1)%2 ## True

नोट: यह अजगर 2 के लिए सही है।


8
यह पायथन 2 के लिए सही हो सकता है, लेकिन निश्चित रूप से पायथन 3 के लिए नहीं (जो कि नहीं है sys.maxint, और जो एक अलग हैश फ़ंक्शन का उपयोग करता है)।
इंटरजेन

0

CPython में पूर्णांक प्रकार के लिए कार्यान्वयन यहां पाया जा सकता।

यह सिर्फ रिटर्न के अलावा, इसके अलावा, मूल्य -1भी लौटाता है -2:

static long
int_hash(PyIntObject *v)
{
    /* XXX If this is changed, you also need to change the way
       Python's long, float and complex types are hashed. */
    long x = v -> ob_ival;
    if (x == -1)
        x = -2;
    return x;
}

6
इसमें बड़े मान शामिल नहीं हैं, जो इसके PyLongबजाय कार्यान्वित किए जाते हैं PyInt
इंटरजेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.