2009-06-08 10 views
3

J'implémente un GetHashCode personnalisé pour la classe System.Drawing.Point en C#. Ma méthode échoue actuellement l'exigence suivante:Générateur de code de hachage le plus rapide .NET

var hashA = MyGetHashCode(new Point(1, 0)); 
var hashB = MyGetHashCode(new Point(0, 1)); 
var hashC = MyGetHashCode(new Point(0, 0)); 
var hashD = MyGetHashCode(new Point(1, 1)); 
Assert.AreNotEqual(hashA^hashB, hashC^hashD); 

Pour réussir ce test, je suis sûr que l'utilisation de nouvelles SHA256Managed() ComputeHash (de currentHash) fera.. Mais il y a un autre algorithme de hachage plus rapide? Je sais que SHA256 est une question de sécurité, et je n'en ai pas besoin.

+1

Comment avez-vous eu l'idée que votre fonction de hachage devrait passer ce test? – mquander

+0

@ mquander Semble sûrement étrange, mais d'autres fonctions Equals de classe reposent sur une implémentation GetHashCode simple, qui à son tour repose sur ma méthode personnalisée Point.GetHashCode –

+0

@mquander Il ne s'agit pas de répéter le code dans Equals et GetHashCode, et de les rendre équivalents. –

Répondre

6

Un hachage simple? Que diriez-vous quelque chose comme:

(17 * point.X) + (23 * point.Y); 

Ou pour l'entropie plus évidente:

int hash = -1047578147; 
hash = (hash * -1521134295) + point.X; 
hash = (hash * -1521134295) + point.Y; 

(numéros de code de type anonyme de C#)

+1

Marc, cela va sûrement remplir l'Assert mais n'est pas borné (un grand X ou Y débordera) ... si vous autorisez un débordement alors il n'a pas une bonne distribution –

+1

Il va s'enrouler (décoché), la distribution est, AFAIK , bien ... C'est l'approche utilisée par le compilateur C# ;-p –

+0

Où obtenez-vous thi s constantes? BTW Jorge a raison. –

1

Je sais que cela ne va pas répondre à votre question, mais Je dois mentionner pour d'autres lecteurs que vous modifiez le comportement par défaut d'une méthode intégrée de l'infrastructure. Selon la documentation:
http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

L'implémentation par défaut de la méthode GetHashCode ne pas garantie des valeurs de retour uniques pour différents objets. En outre, le .NET Framework ne garantit pas l'implémentation par défaut de la méthode GetHashCode, et la valeur qu'elle rendement sera le même entre différentes versions du framework .NET . Par conséquent, l'implémentation par défaut de cette méthode doit être ne doit pas être utilisée comme un objet unique identifiant à des fins de hachage.

+0

Pourriez-vous s'il vous plaît utiliser un blockquote, pas un bloc de code (préférez la citation avec ">" au lieu d'indenter)? Cela rendra la lecture beaucoup plus facile. –

+0

Ce n'est pas un problème dans ce cas. Ce qu'ils veulent dire, c'est que vous ne devriez pas utiliser le GetHashcode par défaut comme valeur unique, parce que différents objets peuvent retourner le même hachage. Quand Jader l'implémente comme une valeur (pratiquement) unique (en utilisant sha256 ou autre), il ne casse rien. Ce sera juste lent ... – tanascius

+0

Pour être honnête, ce sera plutôt lent s'il a vraiment une grosse table de pointage - assez lente pour que ce soit assez ridicule. – mquander

3
  • Pourquoi faites-vous cela? Sûrement System.Drawing.Point a déjà une bonne fonction de hachage? Vous comprenez que le test ne représente pas une exigence stricte, n'est-ce pas? Les codes de hachage ne doivent pas nécessairement être uniques.

  • Si vous voulez vraiment un très bon hachage des coordonnées en question, vous pouvez commencer à this page sur le hachage de plusieurs entiers.

+0

Re "fonction de hachage fine" - x^y ... ce n'est pas génial; cela signifie que tout ce qui est sur la diagonale est nul, et tout ce qui est symétrique, c'est-à-dire (5,7) et (7,5) - est égal. –

+0

Ce n'est pas génial, mais à moins d'avoir une répartition assez pathologique des points, c'est OK. J'ai l'impression que l'OP ne travaille pas sur une exigence de performance concrète, s'il envisage d'utiliser un hachage SHA, donc je doute que quelque chose de mieux soit nécessaire. – mquander

+0

J'ai répondu à la première question dans les commentaires de la question. –

1

Une simple mise en œuvre de hachage Elf (il est en delphi, shoudl facile à traduire)

function ElfHash(id : string; tableSize : integer) : integer; 
var 
    i : integer; 
    h,x : longint; 
begin 
    h := 0; 
    // Obtener el valor numérico 
    for i := 1 to Length(id) do 
    begin 
    h := (h shl 4) + Ord(id[i]); 

    x := h and $F0000000; 
    if x <;>; 0 then 
     h = h xor (x shr 24) xor x; 
    end; 
    // Ajustar al tamaño de la tabla 
    result := h mod tableSize; 
end; 
+0

Je pensais que je savais Delphi, mais je n'ai aucune idée de ce que <;>; –

+0

:) Parlez au code du désinfectant stackoverflow ... C'est "" ovadieusement "" –

+0

Dit "Facile à traduire" en demandant de faire un décalage à gauche, un décalage vers la droite et un code exclusif ou géré. – Hogan

0

Si vous savez à l'avance que votre valeur de point est comprise entre 0 et N, vous pouvez utiliser hashcode = X+Y*N; Ceci est un hachage plutôt évident. Ce n'est pas aléatoire du tout, a une mauvaise répétition, et est généralement assez idiot. Cela équivaut à concaténer les bits de vos deux points, en supposant que N est une puissance de 2. Et qu'il y a une distribution uniforme parfaite et aucune collision.

J'ai utilisé cette stratégie avec un excellent effet dans le passé, mais admettons qu'elle a des limitations réelles (mais évidentes). Le plus grand étant ce qui arrive quand N est assez grand pour que N^2 ne corresponde pas à votre valeur de hachage (collisions douloureuses)

+0

Ma mise en œuvre actuelle est ((x << 16) | (x >> 16))^y (en C#), cela correspond à votre description –

Questions connexes