mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Issue #1772851. Optimization of __hash__ to behave better for big big
numbers.
This commit is contained in:
		
							parent
							
								
									ae406c6018
								
							
						
					
					
						commit
						8c20244069
					
				
					 2 changed files with 43 additions and 4 deletions
				
			
		| 
						 | 
					@ -766,10 +766,17 @@ def __hash__(self):
 | 
				
			||||||
            if self._isnan():
 | 
					            if self._isnan():
 | 
				
			||||||
                raise TypeError('Cannot hash a NaN value.')
 | 
					                raise TypeError('Cannot hash a NaN value.')
 | 
				
			||||||
            return hash(str(self))
 | 
					            return hash(str(self))
 | 
				
			||||||
        i = int(self)
 | 
					        if not self:
 | 
				
			||||||
        if self == Decimal(i):
 | 
					            return 0
 | 
				
			||||||
            return hash(i)
 | 
					        if self._isinteger():
 | 
				
			||||||
        assert self.__nonzero__()   # '-0' handled by integer case
 | 
					            op = _WorkRep(self.to_integral_value())
 | 
				
			||||||
 | 
					            # to make computation feasible for Decimals with large
 | 
				
			||||||
 | 
					            # exponent, we use the fact that hash(n) == hash(m) for
 | 
				
			||||||
 | 
					            # any two nonzero integers n and m such that (i) n and m
 | 
				
			||||||
 | 
					            # have the same sign, and (ii) n is congruent to m modulo
 | 
				
			||||||
 | 
					            # 2**64-1.  So we can replace hash((-1)**s*c*10**e) with
 | 
				
			||||||
 | 
					            # hash((-1)**s*c*pow(10, e, 2**64-1).
 | 
				
			||||||
 | 
					            return hash((-1)**op.sign*op.int*pow(10, op.exp, 2**64-1))
 | 
				
			||||||
        return hash(str(self.normalize()))
 | 
					        return hash(str(self.normalize()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def as_tuple(self):
 | 
					    def as_tuple(self):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -910,6 +910,38 @@ def test_copy_and_deepcopy_methods(self):
 | 
				
			||||||
    def test_hash_method(self):
 | 
					    def test_hash_method(self):
 | 
				
			||||||
        #just that it's hashable
 | 
					        #just that it's hashable
 | 
				
			||||||
        hash(Decimal(23))
 | 
					        hash(Decimal(23))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        test_values = [Decimal(sign*(2**m + n))
 | 
				
			||||||
 | 
					                       for m in [0, 14, 15, 16, 17, 30, 31,
 | 
				
			||||||
 | 
					                                 32, 33, 62, 63, 64, 65, 66]
 | 
				
			||||||
 | 
					                       for n in range(-10, 10)
 | 
				
			||||||
 | 
					                       for sign in [-1, 1]]
 | 
				
			||||||
 | 
					        test_values.extend([
 | 
				
			||||||
 | 
					                Decimal("-0"), # zeros
 | 
				
			||||||
 | 
					                Decimal("0.00"),
 | 
				
			||||||
 | 
					                Decimal("-0.000"),
 | 
				
			||||||
 | 
					                Decimal("0E10"),
 | 
				
			||||||
 | 
					                Decimal("-0E12"),
 | 
				
			||||||
 | 
					                Decimal("10.0"), # negative exponent
 | 
				
			||||||
 | 
					                Decimal("-23.00000"),
 | 
				
			||||||
 | 
					                Decimal("1230E100"), # positive exponent
 | 
				
			||||||
 | 
					                Decimal("-4.5678E50"),
 | 
				
			||||||
 | 
					                # a value for which hash(n) != hash(n % (2**64-1))
 | 
				
			||||||
 | 
					                # in Python pre-2.6
 | 
				
			||||||
 | 
					                Decimal(2**64 + 2**32 - 1),
 | 
				
			||||||
 | 
					                # selection of values which fail with the old (before
 | 
				
			||||||
 | 
					                # version 2.6) long.__hash__
 | 
				
			||||||
 | 
					                Decimal("1.634E100"),
 | 
				
			||||||
 | 
					                Decimal("90.697E100"),
 | 
				
			||||||
 | 
					                Decimal("188.83E100"),
 | 
				
			||||||
 | 
					                Decimal("1652.9E100"),
 | 
				
			||||||
 | 
					                Decimal("56531E100"),
 | 
				
			||||||
 | 
					                ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # check that hash(d) == hash(int(d)) for integral values
 | 
				
			||||||
 | 
					        for value in test_values:
 | 
				
			||||||
 | 
					            self.assertEqual(hash(value), hash(int(value)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #the same hash that to an int
 | 
					        #the same hash that to an int
 | 
				
			||||||
        self.assertEqual(hash(Decimal(23)), hash(23))
 | 
					        self.assertEqual(hash(Decimal(23)), hash(23))
 | 
				
			||||||
        self.assertRaises(TypeError, hash, Decimal('NaN'))
 | 
					        self.assertRaises(TypeError, hash, Decimal('NaN'))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue