3 Stimmen

qHash-Funktion für QRect

Wie berechnet man am besten die qHash Wert einer QRect ? Ich muss verwenden QRect (und vielleicht QRectF ) als den Schlüssel von QCache . Im Moment verwende ich etwas wie dieses:

inline uint qHash(const QRect & r)
{
 return qHash(QByteArray::fromRawData((const char*)&r, sizeof(r)));
}

Es scheint zu funktionieren, aber ich mag es nicht in einige rohe Bytes umzuwandeln, und da QRect keine einfache Struktur ist, könnte dies in zukünftigen Versionen von Qt eher früher als später kaputt gehen.

NEBENBEI BEMERKT. Ich speichere die Hash-Werte nicht, also muss es nicht persistent oder plattformübergreifend sein. Aber es muss zuverlässig und schnell sein.

Merci.

1 Stimmen

Denken Sie zweimal nach, bevor Sie QRectF als QCache-Schlüssel verwenden... denken Sie daran, dass, da QRectF Fließkommawerte enthält, Fließkommafehler auftreten können, und wenn dies der Fall ist, werden sie die von qHash() zurückgegebenen Werte beeinflussen.

0 Stimmen

@Jeremy: Danke für die Warnung. Ich habe das Problem mit den Fließkommazahlen vergessen. Ich werde die Zwischenspeicherung auf der skalierten Pixmap mit Integer-Geometrie durchführen.

0 Stimmen

@Stephen Seien Sie aber auch nicht zu paranoid wegen Rundungsfehlern. Oft müssen zwei leicht unterschiedliche Zahlen (aufgrund von Rundungen) semantisch nicht als dieselbe Zahl behandelt werden.

3voto

Kamil Klimek Punkte 12524

Ich würde einfach tun return qHash(QString("%1,%2,%3,%4").arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height())))

Außerdem habe ich diese Lösung gefunden: http://thesmithfam.org/blog/2008/01/17/using-qrect-with-qhash/ (Kommentar lesen)

1 Stimmen

Danke! Das Hashing der gedruckten Zeichenfolge sollte funktionieren. Aber ich fürchte, es könnte ein bisschen langsamer sein, als es sein muss. Der Kommentar in dem von Ihnen angegebenen Link scheint recht schnell und zuverlässig zu sein. Ich habe es ausprobiert und es scheint recht gut zu funktionieren.

2 Stimmen

Ich würde dies nicht als Allzwecklösung vorschlagen, da der Berechnungsaufwand einfach zu groß ist. Hash-Tabellen sollen schnell sein - also müssen es auch die Hash-Funktionen sein.

1voto

Jeremy Friesner Punkte 63019

Nun, wie wäre es damit:

inline uint qHash(const QRect & r)
{
    return qHash(r.left()) + qHash(r.top()) + qHash(r.width()) + qHash(r.bottom());
}

1 Stimmen

Sorry, aber ich glaube nicht, dass es zuverlässig ist. qHash(int key) macht nur uint(key), es gibt zu viele Datensätze, die den gleichen Datensatz treffen. Für das Rechteck (x:1, y:2, w:3, h:4) wird es auf 1 + 2 + 3 + (unten: 1 + 4) = 11 erweitert. Es besteht ein hohes Risiko, dass ein anderer Datensatz auf denselben qHash-Wert trifft.

0 Stimmen

Kamil hat Recht. Ich habe mir das am Anfang überlegt und festgestellt, dass im Grunde jedes Rechteck mit der gleichen Kombination von x, y, w, h den gleichen Hash ergibt.

1 Stimmen

Zwei verschiedene Rechtecke, die denselben Hash zurückgeben, sind kein Fehler. Wenn Sie das stört, können Sie bestimmte Eingaben multiplizieren, um sie in den Ergebnissen zu unterscheiden.

1voto

leemes Punkte 43469

Wie wäre es mit einer einfachen XOR-Verknüpfung jeder ganzen Zahl? Soweit ich weiß, tut qHash(QPair<..>) dies (mit den bereits berechneten qHashes für beide Elemente).

inline uint qHash(const QRect & r)
{
    return qHash(r.left() ^ r.top() ^ r.right() ^ r.bottom());
    // or
    return qHash(r.left()) ^ qHash(r.top()) ^
           qHash(r.right()) ^ qHash(r.bottom());
}

Dasselbe gilt für QRectF:

inline uint qHash(const QRectF & r)
{
    return qHash(r.left()) ^ qHash(r.top()) ^
           qHash(r.right()) ^ qHash(r.bottom());
}

(Beachten Sie, dass selbst das Abrunden auf ganze Zahlen NICHT bedeutet, dass Ihr Cache nicht richtig funktioniert - die Hashtabelle "schummelt" nur ein wenig).

0voto

Navrocky Punkte 1360

Ich denke, dies ist die optimale Lösung für >=Qt5.4:

uint qHash(const QRect& r)
{
    int data[4];
    data[0] = r.left();
    data[1] = r.top();
    data[2] = r.width();
    data[3] = r.height();
    return qHashBits(data, 4 * sizeof(int));
}

Für Versionen von Qt unter 5.4 müssen wir auf diese Weise weniger optimal schreiben:

uint qHash(const QRect& r)
{
    QByteArray data(sizeof(int) * 4, 0);
    int* d = reinterpret_cast<int*>(data.data());
    d[0] = r.left();
    d[1] = r.top();
    d[2] = r.width();
    d[3] = r.height();
    return qHash(data);
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X