我正在尝试实现自定义哈希方法(乘法):
def h(k, M):
y = hash(k)
T = (math.sqrt(5)-1)/2
return(int(M*((y*T) - int(y * T))))
它总是返回零。我测试了它并(y*T)
- >返回浮点值(例如10,666666
)。 int(y * T)
- >返回整数值(例如10
)。但如果我(y*T) - int(y * T)
,它总是返回0.0
。我的目标是调用类似h('test', 10)
的内容并获取一个数字作为返回值,但它始终返回0.0
。为什么会这样?
答案 0 :(得分:4)
您是在64位系统上运行吗?如果是这样,y
将是64位整数,T
约为0.6,因此,例如,
>>> import random
>>> y = random.randrange(2**64) # some 64-bit int
>>> y
17364376918466400468
>>> yt = y * 0.6
>>> yt
1.041862615107984e+19
>>> yt - int(yt)
0.0
一个浮点数只有53位的精度,因此在将64位int转换为浮点数时,很可能有利于在小数点后面有 no 位。
在32位系统上,hash()
返回32位整数,因此不会出现此问题。
如果此 问题,那么您可以尝试各种解决方法,例如添加:
y = abs(y)
y = (y >> 32) ^ (y & 0xffffffff) # collapse to 32 bits
答案 1 :(得分:1)
此问题源于floating point numbers are stored in a computer的方式。
简而言之:它们存储为有限数量的有效数字,基数和指数。然后计算机知道通过提升到指数的基数来缩放有效数字以获得该值。数据量是机器特定的:对于32位机器,23位用于有效数字,8位用于指数,1用于基数,64位机器将有53位用于sig figs, 8表示指数,1表示基数。
然后通过添加/减去有效数字和指数之间的差异来完成您正在为hash(k)
生成非常大的整数,并尝试在向下舍入的int(y*T)
和浮点y*T
之间取得差异。当Python解释器试图区分float
和int
时,它将int
转换为浮点y*T
将存储一定数量的有效数字。当您尝试从两个高阶幅度数字获得低数量级差异时,或者通常在差异的数量级与所涉及的数字大不相同时,就会出现问题。低阶有效数字将在计算中丢失。
这是我编辑的版本,用于测试您的方法。添加的参数c
是一个常量,我怀疑它将有助于规范化您的结果。
import math
def h(k,M,c):
y = hash(k)
print "hash = ", y
T = (math.sqrt(5)-1)/(2*c)
print "y*T = ", y*T
print "int(y*T) = ", int(y*T)
print "(y*T) - int(y * T) = ",(y*T) - int(y * T)
print "M*((y*T) - int(y * T)) = ", M*((y*T) - int(y * T))
return(int(M*((y*T) - int(y * T))))
print(h('test',2,c))
当你增加c时,基本上使两个数字的差异出现在越来越接近的数量级上,你会开始看到(y*T) - int(y * T)
的值偏离0
。样本输出如下:
>>>h('test',2,10)
hash = 2314058222102390712
y*T = 1.43016663321e+17
int(y*T) = 143016663320543088
(y*T) - int(y * T) = 0.0
M*((y*T) - int(y * T)) = 0.0
h(test,2,10) = 0
>>>h('test',2,1000)
hash = 2314058222102390712
y*T = 1.43016663321e+15
int(y*T) = 1430166633205430
(y*T) - int(y * T) = 0.75
M*((y*T) - int(y * T)) = 1.5
h(test,2,1000) = 1
>>>h('test',2,10000000)
hash = 2314058222102390712
y*T = 1.43016663321e+11
int(y*T) = 143016663320
(y*T) - int(y * T) = 0.543090820312
M*((y*T) - int(y * T)) = 1.08618164062
h(test,2,10000000) = 1
>>>h('test',2,10000000000000)
hash = 2314058222102390712
y*T = 143016.663321
int(y*T) = 143016
(y*T) - int(y * T) = 0.66332054307
M*((y*T) - int(y * T)) = 1.32664108614
h(test,2,10000000000000) = 1
作为我所谈论的现象的另一个例子:
y = hash('test')
print y
y = float(y)
print y
y = int(y)
print y
输出:
2314058222102390712
2.3140582221e+18
2314058222102390784
只需简单地切换到浮点并返回到int,最后两位数字就不再可靠,因此可以看出,此后的任何内容也将丢失。