实现自定义哈希方法

时间:2013-10-29 21:11:14

标签: python algorithm cryptography

我正在尝试实现自定义哈希方法(乘法):

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。为什么会这样?

2 个答案:

答案 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表示基数。

然后通过添加/减去有效数字和指数之间的差异来完成

Addition and Subtraction

您正在为hash(k)生成非常大的整数,并尝试在向下舍入的int(y*T)和浮点y*T之间取得差异。当Python解释器试图区分floatint时,它将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,最后两位数字就不再可靠,因此可以看出,此后的任何内容也将丢失。