值为0.5和1.0的NSNumbers具有相同的哈希值

时间:2014-06-18 10:11:05

标签: ios objective-c nsnumber

有人可以确认并解释为什么会发生这种情况:

在模拟器(7.1,32位)上:

NSNumber *a = [NSNumber numberWithFloat:0.5]; // hash = 506952114
NSNumber *b = [NSNumber numberWithFloat:1.0]; // hash = 2654435761
NSNumber *c = [NSNumber numberWithFloat:2.0]; // hash = 1013904226

在设备上(7.1,32位):

NSNumber *a = [NSNumber numberWithFloat:0.5]; // hash = 2654435761
NSNumber *b = [NSNumber numberWithFloat:1.0]; // hash = 2654435761 - SAME!
NSNumber *c = [NSNumber numberWithFloat:2.0]; // hash = 5308871522

我认为这可能是一个32位的问题,但是当我在64位模拟器和设备上尝试同样的事情时,我得到了相同的问题。模拟器很好,设备有相同的哈希值。

我试图向NSMutableOrderedSet添加唯一对象,并注意到除了0.5和1.0的不同值之外,我的两个相同的对象都没有被添加,这就是原因。我尝试了浮动和双打同样的结果。

但为什么?

2 个答案:

答案 0 :(得分:2)

我认为来自Mike Ash的excellent article可能会提供一些见解:

  

对于整数值的浮点数,我们想要做同样的事情。   因为我们的isEqual:认为整数值DOUBLE等于INT   或UINT具有相同的值,我们必须返回与INT相同的哈希值   UINT等价。为此,我们检查是否有DOUBLE   value实际上是一个整数,如果是这样,则返回整数值:

    if(_value.d == floor(_value.d))
        return [self unsignedIntegerValue];

(我不会引用关于hash的整个部分,所以请阅读该文章以获得完整的披露。)

但是,底线,看起来使用[NSNumber hash]作为关联数组/哈希表中的键是一个坏主意。但是我无法解释为什么它在模拟器和设备下表现不同;这看起来有点令人不安......

答案 1 :(得分:2)

无法保证不同输入的哈希值不同。

在这种情况下,请考虑有2 ^ 32个哈希值,并且有更多唯一NSSNumbers的大小,因此哈希不能用于唯一性。

相当短的哈希通常用作快速初始比较,然后如果它与对象的完全比较匹配。这可能是NSNumber isEqual所做的。

这就是为什么在NSSet中使用哈希作为键是一个坏主意,并且由于@ Ashjanfoe从Mike Ash引用的原因NSNumber哈希将无效。

即使是像SHA512这样的加密哈希也不能保证为不同的输入产生不同的结果,但随着哈希长度的增加,机会很小。这就是为什么MD5建议反对,甚至SHA2越来越被认为是短暂的原因。