This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author Radosław Szalski
Recipients Radosław Szalski, mark.dickinson
Date 2016-06-08.08:04:20
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1465373061.21.0.960848543198.issue27265@psf.upfronthosting.co.za>
In-reply-to
Content
Python 2.7.11 (default, May  9 2016, 19:53:39)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from decimal import Decimal
>>> hash(Decimal('0.05')) == hash(Decimal('0.005'))
True
>>> hash(Decimal(0.05)) == hash(Decimal(0.005))
False

Interactive example: https://repl.it/CZUJ/6

Those values are numerically different and IMO should not have equal hashes. I am aware of the quirk with hash(-1) == hash(-2) which is at play here.
This only applies to Decimals created from strings as they are hashed differently than float-based ones.


What happens? The following equation is True:
>>> hash(Decimal('0.005')) == hash(Decimal('0.05'))

What I expected to happen? The following equation to be False:
>>> hash(Decimal('0.005')) == hash(Decimal('0.05'))


Platform: MacBook Pro Retina, 13", early 2015, OSX 10.11.5
Tested on Python Versions: 2.7.3, 2.7.10, 2.7.11 (installed via pyenv), all exhibit the same behavior


Relevant (not duplicate) issues I've found: 

http://bugs.python.org/issue10356 - decimal.py: hash of -1
http://bugs.python.org/issue8188 - Unified hash for numeric types.



---


Transcript of the interactive example: https://repl.it/CZUJ/6:

from decimal import Decimal

# These two different decimals have equal hashes
print(hash(Decimal('0.005')) == hash(Decimal('0.05')))

# Internally, Decimal's hash is computed like this (sign, exp + len(int), int)
print(hash((0, -2+len('5'), '5')) == hash((0, -3+len('5'), '5')))

# Removing constants, this becomes
print(hash(-2+len('5')) == hash(-3+len('5')))

# Which can be further simplified to:
print(hash(-1) == hash(-2))

# They both return -2, because at the CPython level, -1 is reserved for errors

# Whereas:
print(hash(Decimal(0.005)) == hash(Decimal(0.05)))

# And this is because Decimals created from floats are hashed as floats
History
Date User Action Args
2016-06-08 08:04:21Radosław Szalskisetrecipients: + Radosław Szalski, mark.dickinson
2016-06-08 08:04:21Radosław Szalskisetmessageid: <1465373061.21.0.960848543198.issue27265@psf.upfronthosting.co.za>
2016-06-08 08:04:21Radosław Szalskilinkissue27265 messages
2016-06-08 08:04:20Radosław Szalskicreate