[mpmath] r1220 committed - Changes to support the new hashing algorithm in Python 3.2

3 views
Skip to first unread message

mpm...@googlecode.com

unread,
Jan 16, 2011, 4:41:54 PM1/16/11
to mpmath-...@googlegroups.com
Revision: 1220
Author: casevh
Date: Sun Jan 16 13:41:24 2011
Log: Changes to support the new hashing algorithm in Python 3.2
http://code.google.com/p/mpmath/source/detail?r=1220

Modified:
/trunk/mpmath/libmp/__init__.py
/trunk/mpmath/libmp/backend.py
/trunk/mpmath/libmp/libmpc.py
/trunk/mpmath/libmp/libmpf.py
/trunk/mpmath/rational.py
/trunk/mpmath/tests/test_basic_ops.py

=======================================
--- /trunk/mpmath/libmp/__init__.py Sat Jan 8 14:15:29 2011
+++ /trunk/mpmath/libmp/__init__.py Sun Jan 16 13:41:24 2011
@@ -74,4 +74,5 @@
list_primes, isprime, moebius, gcd, eulernum)

from .backend import (gmpy, sage, BACKEND, STRICT, MPZ, MPZ_TYPE,
- MPZ_ZERO, MPZ_ONE, MPZ_TWO, MPZ_THREE, MPZ_FIVE, int_types)
+ MPZ_ZERO, MPZ_ONE, MPZ_TWO, MPZ_THREE, MPZ_FIVE, int_types,
+ HASH_MODULUS, HASH_BITS)
=======================================
--- /trunk/mpmath/libmp/backend.py Sat Jan 8 15:11:04 2011
+++ /trunk/mpmath/libmp/backend.py Sun Jan 16 13:41:24 2011
@@ -41,6 +41,17 @@
basestring = str
from .exec_py3 import exec_

+# Define constants for calculating hash on Python 3.2.
+if sys.version >= "3.2":
+ HASH_MODULUS = sys.hash_info.modulus
+ if sys.hash_info.width == 32:
+ HASH_BITS = 31
+ else:
+ HASH_BITS = 61
+else:
+ HASH_MODULUS = None
+ HASH_BITS = None
+
if 'MPMATH_NOGMPY' not in os.environ:
try:
try:
=======================================
--- /trunk/mpmath/libmp/libmpc.py Sat Jan 8 14:38:25 2011
+++ /trunk/mpmath/libmp/libmpc.py Sun Jan 16 13:41:24 2011
@@ -2,6 +2,8 @@
Low-level functions for complex arithmetic.
"""

+import sys
+
from .backend import MPZ, MPZ_ZERO, MPZ_ONE, MPZ_TWO, BACKEND

from .libmpf import (\
@@ -14,7 +16,7 @@
mpf_abs, mpf_pos, mpf_neg, mpf_add, mpf_sub, mpf_mul,
mpf_div, mpf_mul_int, mpf_shift, mpf_sqrt, mpf_hypot,
mpf_rdiv_int, mpf_floor, mpf_ceil, mpf_nint, mpf_frac,
- mpf_sign,
+ mpf_sign, mpf_hash,
ComplexResult
)

@@ -63,10 +65,17 @@
return complex(to_float(re, strict), to_float(im, strict))

def mpc_hash(z):
- try:
- return hash(mpc_to_complex(z, strict=True))
- except OverflowError:
- return hash(z)
+ if sys.version >= "3.2":
+ re, im = z
+ h = mpf_hash(re) + sys.hash_info.imag * mpf_hash(im)
+ # Need to reduce either module 2^32 or 2^64
+ h = h % (2**sys.hash_info.width)
+ return int(h)
+ else:
+ try:
+ return hash(mpc_to_complex(z, strict=True))
+ except OverflowError:
+ return hash(z)

def mpc_conjugate(z, prec, rnd=round_fast):
re, im = z
=======================================
--- /trunk/mpmath/libmp/libmpf.py Sat Jan 8 14:54:50 2011
+++ /trunk/mpmath/libmp/libmpf.py Sun Jan 16 13:41:24 2011
@@ -8,12 +8,14 @@

from bisect import bisect

+import sys
+
# Importing random is slow
#from random import getrandbits
getrandbits = None

from .backend import (MPZ, MPZ_TYPE, MPZ_ZERO, MPZ_ONE, MPZ_TWO, MPZ_FIVE,
- BACKEND, STRICT, gmpy, sage, sage_utils)
+ BACKEND, STRICT, HASH_MODULUS, HASH_BITS, gmpy, sage, sage_utils)

from .libintmath import (giant_steps,
trailtable, bctable, lshift, rshift, bitcount, trailing,
@@ -515,14 +517,33 @@
return s == t

def mpf_hash(s):
- try:
- # Try to be compatible with hash values for floats and ints
- return hash(to_float(s, strict=1))
- except OverflowError:
- # We must unfortunately sacrifice compatibility with ints here. We
- # could do hash(man << exp) when the exponent is positive, but
- # this would cause unreasonable inefficiency for large numbers.
- return hash(s)
+ # Duplicate the new hash algorithm introduces in Python 3.2.
+ if sys.version >= "3.2":
+ ssign, sman, sexp, sbc = s
+
+ # Handle special numbers
+ if not sman:
+ if s == fnan: return sys.hash_info.nan
+ if s == finf: return sys.hash_info.inf
+ if s == fninf: return -sys.hash_info.inf
+ h = sman % HASH_MODULUS
+ if sexp >= 0:
+ sexp = sexp % HASH_BITS
+ else:
+ sexp = HASH_BITS - 1 - ((-1 - sexp) % HASH_BITS)
+ h = (h << sexp) % HASH_MODULUS
+ if ssign: h = -h
+ if h == -1: h == -2
+ return int(h)
+ else:
+ try:
+ # Try to be compatible with hash values for floats and ints
+ return hash(to_float(s, strict=1))
+ except OverflowError:
+ # We must unfortunately sacrifice compatibility with ints here.
+ # We could do hash(man << exp) when the exponent is positive,
but
+ # this would cause unreasonable inefficiency for large numbers.
+ return hash(s)

def mpf_cmp(s, t):
"""Compare the raw mpfs s and t. Return -1 if s < t, 0 if s == t,
=======================================
--- /trunk/mpmath/rational.py Sat Jan 8 15:52:03 2011
+++ /trunk/mpmath/rational.py Sun Jan 16 13:41:24 2011
@@ -1,5 +1,6 @@
import operator
-from .libmp import int_types, mpf_hash, bitcount, from_man_exp
+import sys
+from .libmp import int_types, mpf_hash, bitcount, from_man_exp,
HASH_MODULUS

new = object.__new__

@@ -51,12 +52,22 @@

def __hash__(s):
a, b = s._mpq_
- if b == 1:
- return hash(a)
- # Power of two: mpf compatible hash
- if not (b & (b-1)):
- return mpf_hash(from_man_exp(a, 1-bitcount(b)))
- return hash((a,b))
+ if sys.version >= "3.2":
+ inverse = pow(b, HASH_MODULUS-2, HASH_MODULUS)
+ if not inverse:
+ h = sys.hash_info.inf
+ else:
+ h = (abs(a) * inverse) % HASH_MODULUS
+ if a < 0: h = -h
+ if h == -1: h = -2
+ return h
+ else:
+ if b == 1:
+ return hash(a)
+ # Power of two: mpf compatible hash
+ if not (b & (b-1)):
+ return mpf_hash(from_man_exp(a, 1-bitcount(b)))
+ return hash((a,b))

def __eq__(s, t):
ttype = type(t)
=======================================
--- /trunk/mpmath/tests/test_basic_ops.py Sat Jan 8 15:52:03 2011
+++ /trunk/mpmath/tests/test_basic_ops.py Sun Jan 16 13:41:24 2011
@@ -2,6 +2,7 @@
from mpmath import *
from mpmath.libmp import *
import random
+import sys

try:
long = long
@@ -146,6 +147,9 @@
assert hash(mp.mpq(1,1)) == hash(1)
assert hash(mp.mpq(5,1)) == hash(5)
assert hash(mp.mpq(1,2)) == hash(0.5)
+ if sys.version >= "3.2":
+ assert hash(mpf(1))*2**2000 == hash(2**2000)
+ assert hash(mpf(1))/2**2000 == hash(mpq(1,2**2000))

# Advanced rounding test
def test_add_rounding():

Reply all
Reply to author
Forward
0 new messages