如果安全不是问题,那么我认为您所描述的不是哈希函数。散列函数是一种单向函数,这意味着计算散列很容易,但还原它是“困难的”,或者理想情况下是不可能的。
相反,您的要求描述了一个单射函数给定域 X 中的任何 x1, x2,以下成立:
For all x1, x2 element of X, x1 != x2 => f(x1) != f(x2)
f(x) = x 就是这样一个函数,f(x) = x² 不是。简而言之:如果您的输入不同,您希望获得不同的结果,只有输入相同时才能获得相同的结果。确实,对于安全散列也是如此,但它们还提供了单向特性,例如如果仅给定 f(x) 则无法(轻松)找到 x 的属性等。据我了解,您不需要这些安全属性。
简单地说,从现在开始,只需将“字符串字节”解释为“浮点字节”,即可以不同地解释字节(想想 C:
unsigned char *bytes = "...";
double d = (double)bytes;
)。但是,这也有不利之处 - 真正的问题是 Float 具有最大精度,因此如果您的字符串太长,您将遇到溢出情况(浮点数在内部表示为double
值,在 32 位机器上是 8 个字节)。因此几乎没有足够的空间用于任何用例。即使首先对字符串进行 MD5 处理也不能解决问题 - MD5 输出已经有 16 个字节长。
因此,这可能是一个真正的问题,具体取决于您的确切要求。尽管 MD5(或任何其他散列)会与输入充分混淆以使其尽可能随机,但您仍将可能值的范围从 16 个字节减少到有效的 8 个字节。(注意:在保持随机性方面,将随机 16 字节输出截断为 8 个字节通常被认为是“安全的”。椭圆曲线密码学做类似的事情。但据我所知,没有人能真正证明这一点,但也没有人能证明到目前为止相反)。因此,您受限的浮动范围更有可能发生碰撞。根据生日悖论,发现碰撞需要 sqrt(有限范围内的值数)尝试。对于 MD5,这是 2^64,但对于您的方案,它只有 2^32。这仍然非常非常不可能产生碰撞。它' 可能是在中奖的同时被闪电击中的顺序。如果你能忍受这种最小的可能性,那就去做吧:
def string_to_float(str)
Digest::MD5.new.digest(str).unpack('D')
end
如果唯一性是绝对优先级,我建议从浮点数转移到整数。Ruby 内置了对不受long
值的内部约束限制的大整数的支持(这就是 Fixnum 归结为的内容)。因此,任何任意散列输出都可以表示为一个大整数。