Python hash() 函数的正整数

问题描述 投票:0回答:5

我想使用Python

hash()
函数从对象中获取整数哈希值。但内置的
hash()
可以给出负值,而我只想要正值。我希望它能够在 32 位和 64 位平台上正常工作。

即在 32 位 Python 上,

hash()
可以返回
-2**31
2**31 - 1
范围内的整数。 在 64 位系统上,
hash()
可以返回
-2**63
2**63 - 1
范围内的整数。

但我想要 32 位系统上

0
2**32-1
范围内的哈希值,以及 64 位系统上
0
2**64-1
范围内的哈希值。

在 32 位或 64 位目标平台范围内,将哈希值转换为其等效正值的最佳方法是什么?

(上下文:我正在尝试创建一个新的

random.Random
样式类。根据
random.Random.seed()
文档
,种子“可选参数 x 可以是任何可哈希对象。”所以我想复制该功能,除了我的种子算法无法处理负整数值,只能处理正整数值。)

python hash cross-platform
5个回答
32
投票

使用

sys.maxsize

>>> import sys
>>> sys.maxsize
9223372036854775807L
>>> hash('asdf')
-618826466
>>> hash('asdf') % ((sys.maxsize + 1) * 2)
18446744073090725150L

替代使用

ctypes.c_size_t

>>> import ctypes
>>> ctypes.c_size_t(hash('asdf')).value
18446744073090725150L

10
投票

由于显而易见的原因,仅使用

sys.maxsize
是错误的(它是 `2*n-1 而不是 2*n),但修复很简单:

h = hash(obj)
h += sys.maxsize + 1

出于性能原因,您可能希望将 sys.maxsize + 1 拆分为两个单独的分配,以避免为大多数负数临时创建长整数。虽然我怀疑这会很重要


3
投票

(编辑:一开始我以为你一直想要一个 32 位值)

只需将其与所需尺寸的蒙版进行“与”即可。一般来说

sys.maxsize
已经是这样的掩码,因为它是 2 减 1 的幂。

import sys
assert (sys.maxsize & (sys.maxsize+1)) == 0 # checks that maxsize+1 is a power of 2 

new_hash = hash & sys.maxsize

2
投票

怎么样:

h = hash(o)
if h < 0:
  h += sys.maxsize

这使用

sys.maxsize
在 32 位和 64 位系统之间进行移植。


0
投票

要支持带签名和未签名的平台

hash()
,您可以使用

hash(x) % 2**sys.hash_info.width

这将使用 Python 报告的实际哈希宽度,而不是根据 Python 认为的平台上列表的最大大小进行猜测。

注意,如果

x
是接近 0 的整数,则
hash(x)
是恒等函数,即仅传递该值。一般来说,在使用 Python 3.6 的 64 位上,似乎可以计算


(abs(x) % m) * (-1 if x<0 else 1)

m=2**61-1
,第九个梅森素数。这在某些应用程序中可能会出现问题。

© www.soinside.com 2019 - 2024. All rights reserved.