পাইথনে হ্যাশ (এন) == 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

সম্পাদনা: আমি পাইথন ৩ ব্যবহার করছি আমি পাইথন ২ তে একই বাইনারি অনুসন্ধান চালিয়েছি এবং একটি আলাদা ফলাফল পেয়েছি 2147483648, যা আমি মনে করি sys.maxint+1

আমি [hash(random.random()) for i in range(10**6)]হ্যাশ ফাংশনটির পরিসীমা অনুমান করতে খেলি। সর্বাধিক ধারাবাহিকভাবে উপরের n এর নীচে। মিনিটের তুলনায়, পাইথন 3 এর হ্যাশ সর্বদা ইতিবাচকভাবে মূল্যবান বলে মনে হয়, যেখানে পাইথন 2 এর হ্যাশটি নেতিবাচক মান নিতে পারে।


9
আপনি কি সংখ্যাটির বাইনারি উপস্থাপনা পরীক্ষা করেছেন?
জন ডিভোরাক

3
'0b11111111111111111111111111111111111111111111111111111111111111111' কৌতূহল! সুতরাং n+1 == 2**61-1
কর্নেল আতঙ্ক

2
সিস্টেম নির্ভর বলে মনে হচ্ছে। আমার অজগর সহ, হ্যাশটি nপুরো 64 বিট ইনট রেঞ্জের জন্য।
ড্যানিয়েল

1
হ্যাশ মানটির বর্ণিত উদ্দেশ্যটি নোট করুন: অভিধান অনুসন্ধানের সময় এগুলি দ্রুত অভিধান কীগুলি তুলনা করতে ব্যবহৃত হয়। অন্য কথায়, বাস্তবায়ন-সংজ্ঞায়িত এবং হ্যাশ মান থাকতে পারে এমন অনেকগুলি মানের তুলনায় সংক্ষিপ্ত হওয়ার কারণে যুক্তিসঙ্গত ইনপুট স্পেসেও খুব ভাল সংঘর্ষ হতে পারে।
একটি সিএনএন

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 এর হ্যাশটি প্রাইম মোডুলোর হ্রাসের উপর ভিত্তি করে তৈরি হয় P = 2**_PyHASH_BITS - 1। এটি এমনভাবে তৈরি করা হয়েছে যাতে hash(x) == hash(y)x এবং y সংখ্যার সমান হয়, এমনকি যদি x এবং y এর বিভিন্ন ধরণের থাকে।

সুতরাং একটি 64/32 বিট মেশিনের জন্য, হ্রাস 2 _PyHASH_BITS - 1 হবে, তবে কী _PyHASH_BITS?

আপনি এটি pyhash.hহেডার ফাইলটিতে সন্ধান করতে পারেন যা bit৪ বিট মেশিনের জন্য defined১ হিসাবে সংজ্ঞায়িত করা হয়েছে (আপনি pyconfig.hফাইলটিতে আরও ব্যাখ্যা পড়তে পারেন )।

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

সুতরাং প্রথমে এটি আপনার প্ল্যাটফর্মের উপর ভিত্তি করে বন্ধ করুন উদাহরণস্বরূপ আমার bit৪ বিট লিনাক্স প্ল্যাটফর্মে হ্রাস হ্রাস ২ 61 61 -1, যা হ'ল 2305843009213693951:

>>> 2**61 - 1
2305843009213693951

এছাড়াও আপনি math.frexpmant৪ sys.maxintবিট মেশিনের জন্য দেখাতে পারেন যে ম্যান্টিসা এবং উদ্দীপকটি পেতে সর্বোচ্চ সীমা 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। এটি সবচেয়ে বড় মার্সেন প্রাইম যা b৪ বিটের মধ্যে ফিট করে।

যদি আপনাকে কিছু সংখ্যক মান নিয়ে কিছুটা হ্যাশ তৈরি করতে হয় তবে একটি বড় মার্সেন প্রাইম একটি ভাল পছন্দ - এটি গণনা করা সহজ এবং সম্ভাবনার এমনকি বিতরণ নিশ্চিত করে। (যদিও আমি ব্যক্তিগতভাবে কখনও কোনও হ্যাশ তৈরি করতাম না)

ভাসমান পয়েন্ট সংখ্যাগুলির জন্য মডুলাসটি গণনা করা বিশেষত সুবিধাজনক। তাদের একটি ক্ষতিকারক উপাদান রয়েছে যা পুরো সংখ্যাটি দ্বারা গুণ করে 2^x। যেহেতু 2^61 = 1 mod 2^61-1, আপনি শুধুমাত্র বিবেচনা করা প্রয়োজন (exponent) mod 61

দেখুন: https://en.wikedia.org/wiki/Mersenne_prime


8
আপনি বলেছিলেন যে আপনি কখনও এইভাবে একটি হ্যাশ তৈরি করবেন না। কীভাবে এটি এমনভাবে করা যেতে পারে যার জন্য কী কীভাবে এটি কীট, ভাসমান, দশমিক, ভগ্নাংশের গণনা করা যুক্তিসঙ্গতভাবে দক্ষ করে তোলে এবং বিভিন্ন ধরণের x == yগ্যারান্টি নিশ্চিত করে তা নিশ্চিত করার জন্য বিকল্প পরামর্শ আছে hash(x) == hash(y)? ( Decimal('1e99999999')উদাহরণস্বরূপ সংখ্যাগুলি বিশেষত সমস্যাযুক্ত, উদাহরণস্বরূপ: হ্যাশিংয়ের আগে আপনি এগুলি সম্পর্কিত পূর্ণসংখ্যার দিকে প্রসারিত করতে চান না))
মার্ক ডিকিনসন

@ মার্কডিকিনসন আমার সন্দেহ হয় যে তিনি এই সহজ বিদ্যুত্ দ্রুততম হ্যাশ এবং ক্রিপ্টোগ্রাফিক হ্যাশগুলির মধ্যে পার্থক্য আনার চেষ্টা করছেন যা আউটপুটটিকে এলোমেলো দেখায় making
মাইক অংসওয়ার্থ

4
@ মার্কডিকিনসন মডিউলাসটি একটি ভাল শুরু, তবে আমি এটি আরও কিছুটা মিশ্রিত করব, বিশেষত উচ্চ বিটগুলির মধ্যে কিছুটা নিম্নের সাথে মিশ্রিত করব। ২ এর শক্তির দ্বারা বিভাজ্য পূর্ণসংখ্যার ক্রমিকগুলি দেখতে অস্বাভাবিক কিছু নয়, হ্যাশ টেবিলগুলি 2 এর ক্ষমতার ক্ষমতার সাথে দেখতেও অস্বাভাবিক কিছু নয়, উদাহরণস্বরূপ জাভাতে, আপনার যদি 16 এর দ্বারা বিভাজ্য সংখ্যার পূর্ণসংখ্যার ক্রম থাকে এবং এবং আপনি এগুলিকে হ্যাশম্যাপে কী হিসাবে ব্যবহার করেন, আপনি কেবল বালতিগুলির 1/16 তম ব্যবহার করবেন (কমপক্ষে উত্সটিতে আমি যে উত্সটি দেখছি তার সংস্করণে)! আমি মনে করি এই সমস্যাগুলি এড়াতে হ্যাশগুলি কমপক্ষে কিছুটা এলোমেলোভাবে হওয়া উচিত
ম্যাট

হ্যাঁ, বিট-মিক্সিং স্টাইলের হ্যাশগুলি গণিতের অনুপ্রেরণার চেয়ে অনেক বেশি উন্নত। বিট-মিক্সিংয়ের নির্দেশাবলী এত সস্তা যে আপনার একই দামে অনেকগুলি থাকতে পারে। এছাড়াও, বাস্তব বিশ্বের ডেটাগুলিতে এমন নিদর্শনগুলি নেই যা বিট মিক্সিংয়ের সাথে ভালভাবে কাজ করে না । তবে এমন নিদর্শন রয়েছে যা মডিউলাসের জন্য ভয়ঙ্কর।
usr

9
@usr: যে জন্য হ্যাশ কাজ প্রয়োজনীয়তা: অবশ্যই, কিন্তু একটি বিট-মিশ হ্যাশ এখানে infeasible হয় int, float, Decimalএবং Fractionবস্তু এবং যে x == yবোঝা hash(x) == hash(y)এমনকি যখন xএবং yবিভিন্ন ধরনের আছে কিছু বরং তীব্র সীমাবদ্ধতার আরোপ করে। অন্যান্য ধরণের বিষয়ে চিন্তা না করে যদি এটি পূর্ণসংখ্যার জন্য একটি হ্যাশ ফাংশন লেখার বিষয় ছিল তবে এটি সম্পূর্ণ ভিন্ন বিষয়।
মার্ক ডিকিনসন

9

হ্যাশ ফাংশনটি প্লেইন ইনট রিটার্ন করে যার অর্থ হল যে রিটার্ন করা মান এর চেয়ে বেশি -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এন বার পর্যন্ত এটি যে সীমার মধ্যে প্লেইন পূর্ণসংখ্যা উপর স্টপ, উপরের কোড স্নিপেট মত ..

সুতরাং সাধারণত, কোনও এন <= 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 মধ্যে int- এ টাইপ জন্য বাস্তবায়ন এখানে পাওয়া যাবে।

এটি তার পরিবর্তে মান ব্যতীত কেবল ফেরত -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
ইন্টারজয়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.