2014-06-18 1 views
4

Quelqu'un peut-il s'il vous plaît confirmer et expliquer pourquoi cela se produit:NSNumbers ayant une valeur de 0,5 et 1,0 ont le même hachage

sur simulateur (7.1, 32 bits):

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

Sur l'appareil (7.1 , 32 bits):

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 

Je pensais que ce serait peut-être un problème 32 bits, mais lorsque je tente la même chose sur simulateur 64 bits et le dispositif, je reçois le même numéro. Simulateur est bon, l'appareil a des hachages identiques. J'essayais d'ajouter des objets uniques à un NSMutableOrderedSet et j'ai remarqué que mes deux objets qui étaient identiques sauf pour des valeurs différentes de 0.5 et 1.0 n'étaient pas tous les deux ajoutés, et c'est pourquoi. J'ai essayé les deux flotteurs et les doubles avec le même résultat.

Mais pourquoi?

+1

Comprenez-vous le concept de 'hash'? – Sulthan

+0

Eh bien, au meilleur de ma connaissance, c'est un entier non signé qui (je suppose) fournit une référence unique à un objet avec une valeur spécifique ...Mais s'il me manque quelque chose, faites le moi savoir. – jowie

+1

Oui, il vous manque quelque chose, "hash" ne garantit pas l'unicité. C'est comme un code postal. Beaucoup de gens vont partager le même code postal, mais les codes postaux sont toujours d'une grande aide lorsque vous cherchez quelqu'un. 'hash' n'a pas de sens sans si vous n'avez pas un bon' isEqual' aussi. – Sulthan

Répondre

2

Je pense que ce excellent article de Mike Ash pourrait donner un aperçu:

Pour flotteurs qui sont des valeurs entières, nous voulons faire la même chose. Puisque notre isEqual: considère un DOUBLE de valeur entière égal à un INT ou UINT de la même valeur, nous devons retourner le même hachage que l'INT et l'équivalent UINT . Pour ce faire, nous vérifions si la valeur double est en fait un entier, et retourne la valeur entière si oui:

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

(je ne citerai pas toute la section sur les hash, donc s'il vous plaît lire l'article pour une divulgation complète). Mais, en bout de ligne, il semble que l'utilisation de [NSNumber hash] est une mauvaise idée en tant que clé dans une table associative array/hash. Cependant je ne peux pas expliquer pourquoi il se comporte différemment sous le simulateur et l'appareil; cela semble quelque peu troublant ...

+0

Merci ... Mais comment est-ce que je peux écrire le hash de mon objet avec NSNumber pour que les deux objets soient uniques? – jowie

+0

En outre, je ne suis pas concerné par 'isEqual:' car cela ramène effectivement le bon résultat. C'est le hash qui ne marche pas. J'ai aussi remarqué que les hashes de 'NSNumber's entre 0.5 et 0.9 * all * retournent la même valeur. – jowie

+0

@jowie Mais seulement sur l'appareil? Sur le simulateur, on dirait que ça marche? – trojanfoe

2

Il n'y a aucune garantie qu'un hachage pour différentes entrées soit différent.

Dans ce cas, sachez qu'il y a 2^32 valeurs de hachage et qu'il y a des grandeurs plus uniques NSSNumbers donc le hachage ne peut pas être utilisé pour l'unicité.

Un hachage plutôt court est généralement utilisé comme comparaison initiale rapide et ensuite s'il correspond à une comparaison complète de l'objet. C'est probablement ce que fait NSNumberisEqual. C'est pourquoi l'utilisation d'un hachage comme clé dans un NSSet est une mauvaise idée et pour les raisons @trojanfoe citées par Mike Ash, un hachage NSNumber ne fonctionnera pas.

Même les hachages cryptographiques tels que SHA512 ne garantissent pas des résultats différents pour différentes entrées, mais le risque est faible à mesure que la longueur du hachage augmente. C'est pourquoi MD5 est recommandé contre et même SHA2 est de plus en plus considéré comme court.

Questions connexes