]> granicus.if.org Git - python/commitdiff
SF bug #942952: Weakness in tuple hash
authorRaymond Hettinger <python@rcn.com>
Tue, 1 Jun 2004 06:36:24 +0000 (06:36 +0000)
committerRaymond Hettinger <python@rcn.com>
Tue, 1 Jun 2004 06:36:24 +0000 (06:36 +0000)
(Basic approach and test concept by Tim Peters.)

* Improved the hash to reduce collisions.
* Added the torture test to the test suite.

Lib/test/test_tuple.py
Misc/NEWS
Objects/tupleobject.c

index 4fe299f182615d345a429eb0e9250df8fbb77705..a3f40dd07d62e63f910b827c2bb23b49bf4f042d 100644 (file)
@@ -41,6 +41,25 @@ class TupleTest(seq_tests.CommonTest):
                 yield i
         self.assertEqual(list(tuple(f())), range(1000))
 
+    def test_hash(self):
+        # See SF bug 942952:  Weakness in tuple hash
+        # The hash should:
+        #      be non-commutative
+        #      should spread-out closely spaced values
+        #      should not exhibit cancellation in tuples like (x,(x,y))
+        #      should be distinct from element hashes:  hash(x)!=hash((x,))
+        # This test exercises those cases.
+        # For a pure random hash and N=50, the expected number of collisions
+        #      is 7.3.  Here we allow twice that number.
+        #      Any worse and the hash function is sorely suspect.
+
+        N=50
+        base = range(N)
+        xp = [(i, j) for i in base for j in base]
+        inps = base + [(i, j) for i in base for j in xp] + \
+                     [(i, j) for i in xp for j in base] + xp + zip(base)
+        collisions = len(inps) - len(set(map(hash, inps)))
+        self.assert_(collisions <= 15)
 
 def test_main():
     test_support.run_unittest(TupleTest)
index ab705af7bdc56cf6ab185e9f0853f9dea62292e7..2c5dfd9b95f04f5fcc68afba52376a7c8f2f49e3 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.4 alpha 1?
 Core and builtins
 -----------------
 
+- Improved the tuple hashing algorithm to give fewer collisions in
+  common cases.  Fixes bug  #942952.
+
 - Implemented generator expressions (PEP 289).  Coded by Jiwon Seo.
 
 - Enabled the profiling of C extension functions (and builtins) - check
index 159dc44fd07e7ee28622fb835f46a8eea5dd9912..4cb80f0ed50a1e9aa64f0b9bb52768f709e40e36 100644 (file)
@@ -262,15 +262,16 @@ tuplehash(PyTupleObject *v)
        register long x, y;
        register int len = v->ob_size;
        register PyObject **p;
+       long mult = 1000003L;
        x = 0x345678L;
        p = v->ob_item;
        while (--len >= 0) {
                y = PyObject_Hash(*p++);
                if (y == -1)
                        return -1;
-               x = (1000003*x) ^ y;
+               x = (x ^ y) * mult;
+               mult += 69068L + len + len;
        }
-       x ^= v->ob_size;
        if (x == -1)
                x = -2;
        return x;