Resumo: não é uma coincidência; _PyHASH_INF
é codificado como 314159 na implementação CPython padrão do Python e foi escolhido como um valor arbitrário (obviamente dos dígitos de π) por Tim Peters em 2000 .
O valor de hash(float('inf'))
é um dos parâmetros dependentes do sistema da função de hash interna para tipos numéricos e também está disponível como sys.hash_info.inf
no Python 3:
>>> import sys
>>> 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)
>>> sys.hash_info.inf
314159
(Mesmos resultados com o PyPy também.)
Em termos de código, hash
é uma função interna. A chamada para um objeto flutuante Python chama a função cujo ponteiro é fornecido pelo tp_hash
atributo do tipo flutuante interno ( PyTypeObject PyFloat_Type
), que é a float_hash
função definida como return _Py_HashDouble(v->ob_fval)
, que por sua vez possui
if (Py_IS_INFINITY(v))
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
onde _PyHASH_INF
é definido como 314159:
#define _PyHASH_INF 314159
Em termos de histórico, a primeira menção 314159
nesse contexto no código Python (você pode encontrar isso com git bisect
ou git log -S 314159 -p
) foi adicionada por Tim Peters em agosto de 2000, no que agora é commit 39dce293 no cpython
repositório git.
A mensagem de confirmação diz:
Correção para http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470 . Este foi um erro enganoso - o verdadeiro "erro" foi o que hash(x)
deu um retorno de erro quando x
é um infinito. Corrigido isso. Adicionada nova Py_IS_INFINITY
macro a
pyport.h
. Código reorganizado para reduzir a duplicação crescente no hash de números flutuantes e complexos, levando a facada anterior de Trent a uma conclusão lógica. Corrigido um erro extremamente raro em que o hash de flutuadores podia retornar -1, mesmo que não houvesse um erro (não perdia tempo tentando construir um caso de teste, era óbvio pelo código que isso poderia acontecer). Hash complexo aprimorado para que
hash(complex(x, y))
não seja hash(complex(y, x))
mais igual sistematicamente .
Em particular, nesse commit, ele rasgou o código de static long float_hash(PyFloatObject *v)
in Objects/floatobject.c
e o fez apenas return _Py_HashDouble(v->ob_fval);
, e na definição de long _Py_HashDouble(double v)
in Objects/object.c
ele adicionou as linhas:
if (Py_IS_INFINITY(intpart))
/* can't convert to long int -- arbitrary */
v = v < 0 ? -271828.0 : 314159.0;
Então, como mencionado, foi uma escolha arbitrária. Observe que 271828 é formado a partir dos primeiros dígitos decimais de e .
Commits posteriores relacionados:
Por Mark Dickinson em abril de 2010 ( também ), fazendo o Decimal
tipo se comportar de maneira semelhante
Por Mark Dickinson em abril de 2010 ( também ), movendo essa verificação para o topo e adicionando casos de teste
Por Mark Dickinson, em maio de 2010, como edição 8188 , reescrevendo completamente a função hash para sua implementação atual , mas mantendo esse caso especial, fornecendo um nome à constante _PyHASH_INF
(também removendo o 271828, é por isso que no Python 3 hash(float('-inf'))
retorna -314159
mais do -271828
que no Python 2)
Por Raymond Hettinger em janeiro de 2011 , adicionando um exemplo explícito no "What's new" para Python 3.2 de sys.hash_info
mostrar o valor acima. (Veja aqui .)
Por Stefan Krah em março de 2012 modificando o módulo Decimal, mas mantendo esse hash.
Por Christian Heimes em novembro de 2013 , mudou-se a definição de _PyHASH_INF
partir Include/pyport.h
para Include/pyhash.h
onde ele vive agora.
hash(float('nan'))
é0
.