String #hash方法可以在Ruby中返回的最大值是多少?

时间:2015-03-27 14:38:40

标签: ruby

标题说明了这一点,Ruby中'some random string'.hash可以返回的最大值是什么?

docs没有提供太多见解。

2 个答案:

答案 0 :(得分:2)

可输出的最大尺寸String#hash似乎是您环境中unsigned long的最大尺寸。

String#hash功能在rb_str_hash()中实现:

/* string.c, l. 2290 */

st_index_t
rb_str_hash(VALUE str)
{
    int e = ENCODING_GET(str);
    if (e && rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT) {
        e = 0;
    }
    return rb_memhash((const void *)RSTRING_PTR(str), RSTRING_LEN(str)) ^ e;
}

st_index_t定义为类型st_data_t

/* st.h, l. 48 */

typedef st_data_t st_index_t;

st_data_tunsigned long

/* st.h, l. 20 */

typedef unsigned long st_data_t;

由于散列是随机生成的(使用SipHash),因此unsigned long中可能的整个值范围都应该可用。在64位环境中,unsigned long当然是64位。 SipHash的输出是64位,因此在32位环境中,Ruby将其输出存储在一个带有两个32位无符号整数的数组中,rb_memhash()将它们与按位异或组合。

in siphash.h:

/* siphash.h, l. 14 */

#ifndef HAVE_UINT64_T
typedef struct {
    uint32_t u32[2];
} sip_uint64_t;
#define uint64_t sip_uint64_t
#else
typedef uint64_t sip_uint64_t;
#endif

rb_memhash()

/* random.c, l. 1306 */

st_index_t
rb_memhash(const void *ptr, long len)
{
    sip_uint64_t h = sip_hash24(sipseed.key, ptr, len);
    #ifdef HAVE_UINT64_T
        return (st_index_t)h;
    #else
        return (st_index_t)(h.u32[0] ^ h.u32[1]);
    #endif
}

这是Ruby的sip_hash24(),如果你想看一下这个实现。

答案 1 :(得分:1)

Object#hash method返回a Fixnum,其中:

  

保存可以在本机机器字(减1位)中表示的整数值。

令人讨厌的是,似乎没有一种简单的方法可以确定特定系统的确切最大值(有一个open feature request by Matz - #7517),所以你必须自己计算它。

下面的示例代码(https://stackoverflow.com/a/736313/244128)适用于某些Ruby平台,但不能在所有这些平台上可靠地运行:

FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))