In dieser Code-Challenge schreiben Sie eine Hash-Funktion in 140 Byte 1 oder weniger Quellcode. Die Hash-Funktion muss eine ASCII-Zeichenfolge als Eingabe annehmen und eine vorzeichenlose 24-Bit-Ganzzahl ([0, 2 24 -1]) als Ausgabe zurückgeben.
Ihre Hash-Funktion wird für jedes Wort in diesem großen Britisch-Englisch-Wörterbuch 2 ausgewertet . Ihre Punktzahl ist die Anzahl der Wörter, die einen Hash-Wert mit einem anderen Wort teilen (eine Kollision).
Die niedrigste Punktzahl gewinnt, Unentschieden durch das erste Plakat.
Testfall
Testen Sie Ihr Scoring-Skript vor dem Absenden anhand der folgenden Eingabe:
duplicate
duplicate
duplicate
duplicate
Wenn es eine andere Punktzahl als 4 gibt, ist es fehlerhaft.
Regeln klären:
- Ihre Hash-Funktion muss mit einer einzelnen Zeichenfolge ausgeführt werden, nicht mit einem ganzen Array. Außerdem führt Ihre Hash-Funktion möglicherweise keine anderen E / A-Vorgänge als die Eingabezeichenfolge und die Ausgabe-Ganzzahl aus.
- Eingebaute Hash-Funktionen oder ähnliche Funktionen (z. B. Verschlüsselung für verwürfelte Bytes) sind nicht zulässig.
- Ihre Hash-Funktion muss deterministisch sein.
- Im Gegensatz zu den meisten anderen Wettbewerben ist die Optimierung speziell für die Bewertungseingabe zulässig.
1 Ich bin mir bewusst, dass Twitter Zeichen anstelle von Bytes begrenzt, aber der Einfachheit halber werden wir Bytes als Grenze für diese Herausforderung verwenden.
2 Geändert von Debians britisch-riesigem Format , wobei alle Nicht-ASCII-Wörter entfernt werden.
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch's
? Was zum...?D=340275
Wörtern undR=2^24
Hash-Ausgaben hat ein zufälliger Hash erwarteteD^2/(2*R) = 3450
kollidierende Paare, von denen sich einige überlappen. Es gibt erwarteteD^3/(6*R^2) = 23
kollidierende Tripel und eine vernachlässigbare Anzahl größerer Kollisionen, was bedeutet, dass diese Tripel wahrscheinlich disjunkt sind. Dies ergibt erwartete6829
Wörter, die einen Hash-Wert teilen, ~70
in Dreiergruppen und den Rest in Paaren. Die Standardabweichung wird auf geschätzt118
, so dass das Erhalten<6200
eines zufälligen Hash ungefähr ein 5-Sigma-Ereignis ist.Antworten:
In Ordnung, ich werde eine Golfsprache lernen.
CJam, 140 Bytes, 3314 kollidierende Wörter
Definiert einen Block (anonyme Funktion). Zum Testen können Sie hinzufügen
qN%%N*N
, dass Sie die durch Zeilenumbrüche getrennte Liste von Wörtern in stdin aufnehmen und eine durch Zeilenumbrüche getrennte Liste von Hashes in stdout schreiben. Äquivalenter Python-Code:Pyth, 140 Bytes,
35353396 kollidierende WörterDefiniert eine Funktion mit dem Namen
y
. Zum Testen können Sie hinzufügenjmyd.z
, dass Sie die durch Zeilenumbrüche getrennte Liste von Wörtern in stdin aufnehmen und eine durch Zeilenumbrüche getrennte Liste von Hashes in stdout schreiben. Äquivalenter Python-Code:Theoretische Grenzen
Wie gut können wir damit rechnen? Hier ist eine grafische Darstellung von x, der Anzahl der kollidierenden Wörter, und y, der Entropie in Bytes, die erforderlich ist, um höchstens x kollidierende Wörter zu erhalten. Zum Beispiel sagt uns der Punkt (2835, 140), dass eine Zufallsfunktion höchstens 2835 kollidierende Wörter mit einer Wahrscheinlichkeit von 1/256 ** 140 erhält, so dass es äußerst unwahrscheinlich ist, dass wir jemals in der Lage sein werden, viel besser als mit 140 zu werden Byte Code.
quelle
Python,
53334991Ich glaube, dies ist der erste Anwärter, der deutlich besser abschneidet als ein zufälliges Orakel.
quelle
def H(s):n=int(s.encode('hex'),16);return n%...
spart 5 Bytes, falls Sie sie irgendwie verwenden können ...2**24 == 8**8
.Python 2, 140 Bytes, 4266 kollidierende Wörter
Ich wollte nicht wirklich mit der nicht druckbaren Bytes-Sache anfangen, da ihre Tweet-Fähigkeit unklar ist, aber nun, ich habe sie nicht gestartet. :-P
Python 2, 140 druckbare Bytes,
466244714362 kollidierende WörterInspiriert von der Form von Kasperds Lösung - aber mit der wichtigen Hinzufügung einer affinen Transformation auf den Modulraum und völlig anderen Parametern.
quelle
n%(8**8-ord('…'[n%70]))
ohne andere Parameteränderungen hatte ich es nur geschafft, auf 4995 zu kommen. Es sieht also so aus, als hätte Ihr neuer Optimierer meine eingeholt. Das wird jetzt interessanter!CJam,
4125393737913677Dieser Ansatz unterteilt Domain und Codomain in 110 disjunkte Mengen und definiert für jedes Paar eine etwas andere Hash-Funktion.
Wertung / Verifikation
Der folgende Port für Python kann mit dem offiziellen Scoring-Snippet verwendet werden:
quelle
h
dieser Python-Port einem eingebauten CJam?b
( Basisumwandlung ).Python,
64466372Diese Lösung erzielt eine geringere Anzahl von Kollisionen als alle vorherigen Einträge und benötigt nur 44 der 140 für den Code zulässigen Bytes:
quelle
%(2**24-1)
, so denke ich, es könnte gut sein, um Klärung zu bitten[0, 2**24-1]
als Wörter in der englischen Sprache gibt, wäre es mathematisch unmöglich , einen Hash zu erstellen , bei dem jeder einzelne Wert in diesem Bereich möglich wäre.CJam, 6273
XOR jedes Zeichen mit 49 , reduziere den resultierenden String mit x, y ↦ 245x + y und nimm das Residuum Modulo 16.777.213 (die größte 24-Bit-Primzahl).
Wertung
quelle
JavaScript (ES6), 6389
Die Hash-Funktion (105 Bytes):
Die Bewertungsfunktion (NodeJS) (170 Bytes):
Rufe auf als
node hash.js dictionary.txt
, wohash.js
ist das Skript,dictionary.txt
ist die Wörterbuch-Textdatei (ohne die letzte neue Zeile) undF
ist als die Hash-Funktion definiert.Vielen Dank, Neil, dass du 9 Bytes von der Hashing-Funktion entfernt hast!
quelle
((...)>>>0)%(1<<24)
kann man wahrscheinlich anstelle von verwenden(...)<<8>>>8
.i
interessieren.Mathematica, 6473
Der nächste Schritt nach oben ... Anstatt die Zeichencodes zu summieren, behandeln wir sie als die Ziffern einer Basis-151-Zahl, bevor wir sie modulo 2 24 nehmen .
Hier ist ein kurzes Skript, um die Anzahl der Kollisionen zu bestimmen:
Ich habe gerade alle Basen systematisch von Anfang an ausprobiert
1
und bis jetzt ergab Basis 151 die wenigsten Kollisionen. Ich werde ein paar mehr versuchen, um die Punktzahl weiter zu senken, aber das Testen ist etwas langsam.quelle
Javascript (ES5), 6765
Dies ist CRC24 bis zu 140 Bytes rasiert. Könnte mehr Golf spielen, wollte aber meine Antwort bekommen :)
Validator in node.js:
quelle
Python, 340053
Eine schreckliche Punktzahl von einem schrecklichen Algorithmus. Diese Antwort gibt eher ein kleines Python-Skript an, das die Punktzahl anzeigt.
Um zu punkten:
quelle
Python,
6390,6376,6359Kann als geringfügige Änderung der Antwort von Martin Büttner angesehen werden .
quelle
[0, 2**24-1]
. Das einzige, was nicht erlaubt ist, ist die Ausgabe einer Nummer, die nicht in diesem Bereich liegt, zB-1
oder2**24
.Python, 9310
Ja, nicht das Beste, aber zumindest ist es etwas. Wie wir in Krypto sagen, schreiben Sie niemals Ihre eigene Hash-Funktion .
Dies ist ebenfalls genau 140 Byte lang.
quelle
Matlab,
3082886206848Es bildet den Hash, indem es jeder ASCII-Zeichen- / Positionskombination eine Primzahl zuweist und für jedes Wortmodul die größte Primzahl berechnet, die kleiner als 2 ^ 24 ist. Beachten Sie, dass ich zu Testzwecken den Aufruf von primes außerhalb direkt vor der while-Schleife in den Tester verschoben und an die Hash-Funktion übergeben habe, da er die Geschwindigkeit um den Faktor 1000 erhöht hat, diese Version jedoch funktioniert und in sich geschlossen ist. Bei Wörtern, die länger als 40 Zeichen sind, kann es zu einem Absturz kommen.
Prüfer:
quelle
double
explizit in ein konvertieren . Auch könnte mannumel
eher als gebrauchenlength
. Nicht sicher, was Sie mit all den zusätzlichen Bytes machen würden!Ruby, 9309 Kollisionen, 107 Bytes
Kein guter Anwärter, aber ich wollte eine andere Idee als andere Einträge untersuchen.
Weisen Sie die ersten n Primzahlen den ersten n Positionen der Zeichenfolge zu, summieren Sie dann alle Primzahlen [i] ** (ASCII-Code der Zeichenfolge [i]) und dann mod 2 ** 24-1.
quelle
Java 8,
70546467Dies wurde von der eingebauten Funktion java.lang.String.hashCode inspiriert (aber nicht kopiert).
Um zu punkten:
quelle
hashes
mitMap<Integer, Integer> hashes = new HashMap<>()
und dann die Anzahl der Wörter für jeden Hash zählen, können Sie richtig für sie berücksichtigen.Python,
699568626732Nur eine einfache RSA-Funktion. Ziemlich lahm, schlägt aber einige Antworten.
quelle
C ++:
711266946483647964126339 Kollisionen, 90 BytesIch habe einen naiven genetischen Algorithmus für mein Koeffizientenarray implementiert. Ich werde diesen Code aktualisieren, da er bessere findet. :)
Testfunktion:
quelle
C #, 6251
6335Die Konstanten 533 und 733,
889 und 155geben die beste Punktzahl von allen, die ich bisher gesucht habe.quelle
tcl
88 Bytes, 6448/3233 Kollisionen
Ich sehe, dass die Leute entweder die Anzahl der kollidierenden Wörter oder die Anzahl der Wörter in nicht leeren Eimern gezählt haben. Ich gebe beide Zählungen an - die erste entspricht der Problemspezifikation, und die zweite ist das, worüber mehr Plakate berichtet haben.
quelle
proc H w {incr h;lmap c [split $w {}] {set h [expr (2551*$h+[scan $c %c])%2**24]};set h}
... richtig?Python 3, 89 Bytes, 6534 Hash-Kollisionen
Alle großen magischen Zahlen, die Sie hier sehen, sind Fudge-Konstanten.
quelle
JavaScript, 121 Byte,
3268325032446354 (3185) KollisionenDie Parameter (13, 7809064, 380886, 2, 266324) werden durch Ausprobieren ermittelt.
Ich denke immer noch optimierbar, und es gibt immer noch Raum für das Hinzufügen zusätzlicher Parameter, die für die weitere Optimierung arbeiten ...
Nachprüfung
3268> 3250 - Der 3. Parameter wurde von 380713 in 380560 geändert.
3250> 3244 - Der 3. Parameter wurde von 380560 in 380886 geändert.
3244> 6354 - Der zweite Parameter wurde von 7809143 in 7809064 geändert, und ich habe festgestellt, dass ich die falsche Berechnungsmethode verwendet habe
quelle
Hier einige ähnliche Konstrukte, die durchaus "seedbar" sind und eine inkrementelle Parameteroptimierung ermöglichen. Verdammt, es ist schwierig, unter 6 km zu kommen! Unter der Annahme, dass die Punktzahl den Mittelwert von 6829 und den Standardwert von 118 hat, berechnete ich auch die Wahrscheinlichkeit, zufällig so niedrige Punktzahlen zu erhalten.
Clojure A, 6019, Pr = 1: 299,5e9
Clojure B, 6021, Pr = 1: 266,0e9
Clojure C, 6148, Pr = 1: 254,0e6
Clojure, 6431, Pr = 1: 2.69e3 (etwas anderes)
Dies war meine ursprüngliche Ad-hoc-Hash-Funktion. Sie verfügt über vier einstellbare Parameter.
quelle
r
festgelegt ist). Trotzdem ist mein Suchalgorithmus im Wesentlichen brachial und ich bin nicht sicher, ob die anfängliche Wahl des Multiplikators vonr
Bedeutung ist oder nicht.f(n) % (8^8 - g(n))
.Ruby, 6473 Kollisionen, 129 Bytes
Die Variable @p ist mit allen Primzahlen unter 999 gefüllt.
Dies konvertiert ASCII-Werte in Primzahlen und nimmt ihrem Produktmodul eine große Primzahl. Der Fudge-Faktor von 179 befasst sich mit der Tatsache, dass der ursprüngliche Algorithmus zum Auffinden von Anagrammen verwendet wurde, bei denen alle Wörter, die Umordnungen derselben Buchstaben sind, denselben Hash erhalten. Durch Hinzufügen des Faktors in der Schleife werden Anagramme mit unterschiedlichen Codes versehen.
Ich könnte die ** 0.5 (sqrt test for prime) auf Kosten einer schlechteren Leistung entfernen, um den Code zu verkürzen. Ich könnte sogar veranlassen, dass der Primzahlfinder in der Schleife ausgeführt wird, um neun weitere Zeichen zu entfernen, wobei 115 Bytes übrig bleiben.
Zum Testen wird folgendermaßen versucht, den besten Wert für den Fudge-Faktor im Bereich von 1 bis 300 zu finden. Dabei wird davon ausgegangen, dass sich die Wortdatei im Verzeichnis / tmp befindet:
quelle
tcl
# 91 Bytes, 6508 Kollisionen91 Bytes, 6502 Kollisionen
Der Computer führt immer noch eine Suche durch, um festzustellen, ob ein Wert vorliegt, der weniger Kollisionen verursacht als die
147875-Basis, bei der es sich immer noch um den Rekorder handelt.quelle