Was ist ein angemessenes `GetHashCode ()` - Algorithmus für ein 2D point struct (Vermeidung von Zusammenstößen)
Betrachten Sie den folgenden code:
struct Vec2 : IEquatable<Vec2>
{
double X,Y;
public bool Equals(Vec2 other)
{
return X.Equals(other.X) && Y.Equals(other.Y);
}
public override bool Equals(object obj)
{
if (obj is Vec2)
{
return Equals((Vec2)obj);
}
return false;
}
//this will return the same value when X, Y are swapped
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
}
Jenseits der Unterhaltung zu vergleichen, verdoppelt sich für die Gleichstellung (das ist nur demo-code), was ich befürchte, ist, dass ein hash-clash, wenn X, Y Werte werden vertauscht. Zum Beispiel:
Vec2 A = new Vec2() { X=1, Y=5 };
Vec2 B = new Vec2() { X=5, Y=1 };
bool test1 = A.Equals(B); //returns false;
bool test2 = A.GetHashCode() == B.GetHashCode() //returns true !!!!!
sollte Wrack Chaos in der dictionary-Auflistung. Die Frage ist also, wie man Eigentum bilden die GetHashCode()
- Funktion für 2, 3 oder sogar 4 floating-point-Werte so, dass die Ergebnisse sind nicht symmetrisch und die hashes nicht zur Deckung zu bringen.
Edit 1:
Point
implementiert die unangemessene x ^ y
Lösung, und PointF
wraps ValueType.GetHashCode()
.
Rectangle
hat einen sehr eigenartigen (((X ^ ((Y << 13) | (Y >> 19))) ^ ((Width << 26) | (Width >> 6))) ^ ((Height << 7) | (Height >> 25)))
Ausdruck für die hash-code, die scheint, wie erwartet.
Edit 2:
'- System.Double' hat eine schöne Umsetzung, wie er betrachtet nicht jedes bit ebenso wichtig
public override unsafe int GetHashCode() //from System.Double
{
double num = this;
if (num == 0.0)
{
return 0;
}
long num2 = *((long*) &num);
return (((int) num2) ^ ((int) (num2 >> 32)));
}
Hashes wird clash -
int
hat einen kleineren Bereich der möglichen Werte als double
, und es ist sogar noch kleiner, wenn im Vergleich zu double
xdouble
. Auch, möchten Sie vielleicht zu prüfen, ein loser, der Geschlechter-Vergleich - bedingt durch die Rundung, zwei float-Werte können sehr nahe beieinander (was jemand tut, ein Vergleich "mit dem Auge" betrachten würden gleich), aber doch nicht genau gleich sein.Es ist nicht nur, dass (A,B) kollidiert mit (B,A). Dank der Tatsache, dass X^X --> 0 es werden alle (C,C) kollidiert mit all (D,D), und das ist ein viel größerer Raum von Kollisionen.
mögliche Duplikate von Erstellen Sie ein hashcode von zwei zahlen
InformationsquelleAutor ja72 | 2011-03-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
Jon skeet ist dieses abgedeckt:
Was ist der beste Algorithmus für eine überschriebene System.Objekt.GetHashCode?
ändern Sie Auch IhreEquals(object)
Umsetzung:Beachten Sie jedoch, dass dies wahrnehmen könnte einen abgeleiteten Typ zu gleich. Wenn Sie das nicht wollen, würden Sie vergleichen die runtime-TypDanke für den Hinweis heraus, es ist ein struct, LukHother.GetType()
mittypeof(FVector2)
(und vergessen Sie nicht, die Nichtigkeit überprüft)Resharper hat schöne code-Generierung für Gleichheit und hash-code, so dass, wenn Sie haben resharper Sie können lassen Sie es seine Sache
Equals(object)
Umsetzung kann nicht geändert werdenas
. Es ist nichts falsch mit den OP ' s aktuelleEquals(object)
Methode.Dies kann gut funktionieren, aber wenn Sie einen Blick in die Berechnung für
Double.GetHashCode()
Sie werden feststellen, dass eine sorgfältige Berücksichtigung von wichtigen bits verwendet wird, und ich möchte, um Klage zu Folgen.Danke für die Antwort, wie ich bereits implementiert, eine version für die vielen Strukturen da.
Gern behilflich sein !
InformationsquelleAutor Ohad Schneider
Hash-Kollisionen nicht verheerend in einem Wörterbuch Sammlung. Sie senken die Effizienz, wenn Sie Pech haben genug, um Sie zu bekommen, sondern Wörterbücher haben, um mit Ihnen umzugehen.
Kollisionen sollten selten, wenn überhaupt möglich, aber Sie sind nicht meine, die Umsetzung ist falsch. XORs sind oft schlecht für die Gründe, die Sie gegeben haben (high-Kollisionen) - ohadsc gepostet hat, eine Probe, die ich gab, bevor Sie für eine alternative, die sollten in Ordnung sein.
Beachten Sie, dass es unmöglich wäre, das zu implementieren
Vec2
mit keine Kollisionen - es gibt nur 232 mögliche Rückgabewerte vonGetHashCode
, aber es sind eher möglich, die X-und Y-Werte, auch nachdem Sie entfernt haben NaN und unendlich vielen Werte...Eric Lippert hat eine letzten blog-post auf
GetHashCode
die Sie nützlich finden können.Evtl. Es hängt davon ab, die Daten aus der realen Welt. Wenn Sie dazu neigen, tatsächlich, um ganze zahlen, wird es noch böse sein.
InformationsquelleAutor Jon Skeet
Was sind angemessene Grenzen für die Koordinaten?
Es sei denn, es können alle möglichen integer-Werte können Sie einfach:
const SOME_LARGE_NUMBER=100000;
zurück SOME_LARGE_NUMBER * x + y;
int
s auch mitint.MaxValue
mitunchecked
- KlauselInformationsquelleAutor KristoferA
Wenn die Größe der hash-code ist kleiner als die Größe der struct, dann sind Auseinandersetzungen unvermeidlich sind, sowieso.
InformationsquelleAutor arrowd
Des hash-codes Ansatz funktioniert für die interger-Koordinaten, ist aber nicht empfohlen für die floating-point-Werte. Mit Gleitkomma-Koordinaten kann man einen Punkt-Satz/pool mithilfe einer sortierten Sequenz-Struktur.
Einer sortierten Sequenz ist eine leaf-version ausgeglichenen binären Baum.
Hier der Schlüssel wäre die Punkt-Koordinaten.
GetHashCode()
nicht deterministischen, aber ich verstehe nicht, wie Sie vorschlagen, dies zu umgehen.Vergessen Sie GetHashCode(), die Sie nicht verwenden hashing. Nur ein ausgeglichener binärer Baum mit einem xy-Komparator.
Ich habe oft die Notwendigkeit zur Umsetzung
IEquatable<>
und somit hashing erforderlich ist, zu überschreiben. Können Sie bitte zeigen Sie einige code, so können wir verstehen, was Sie reden.Btw, können Sie konvertieren Ganzzahlen, die Verwendung von einem raster dann bekommen hashing ohne Kollisionen durch die Verwendung einer dieser Funktionen. dmauro.com/post/77011214305/...
Mapping zwei ganze zahlen, die eine eindeutige und deterministische Weise. stackoverflow.com/questions/919612/...
InformationsquelleAutor mszlazak