Erstellen Sie eine einheitliche Zufallszahl basiert auf einer hash
Ich brauche einen guten pseudo-random-Zahl, basierend auf einem Schlüssel, der aus einem string und einem langen. Ich sollte die gleiche Zufallszahl, wenn ich die Abfrage mit dem gleichen Schlüssel und auch, ich sollte bekommen eine ganz andere Nummer, wenn ich die Abfrage mit einem etwas anderen Schlüssel, auch wenn Sie sagen, die lange in der Taste aus ist, indem 1. Ich habe versucht, diesen code und die Zufallszahlen eindeutig sind, aber für ähnliche zahlen Sie scheinen korreliert.
import java.util.Date;
import java.util.Random;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class HashKeyTest {
long time;
String str;
public HashKeyTest(String str, long time) {
this.time = time;
this.str = str;
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(time).append(str).toHashCode();
}
public static void main(String[] args) throws Exception {
for(int i=0; i<10; i++){
long time = new Date().getTime();
HashKeyTest hk = new HashKeyTest("SPY", time);
long hashCode = (long)hk.hashCode();
Random rGen = new Random(hashCode);
System.out.format("%d:%d:%10.12f\n", time, hashCode, rGen.nextDouble());
Thread.sleep(1);
}
}
}
Lösung, die ich mir zusammengebastelt. Das funktioniert ziemlich gut, aber ich Frage mich, ob es braucht, um diese ausführlich.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
public class HashKeyTest implements Serializable{
long time;
String str;
public HashKeyTest(String str, long time) {
this.time = time;
this.str = str;
}
public double random() throws IOException, NoSuchAlgorithmException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(this);
byte[] bytes = bos.toByteArray();
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
byte[] hash = md5Digest.digest(bytes);
ByteBuffer bb = ByteBuffer.wrap(hash);
long seed = bb.getLong();
return new Random(seed).nextDouble();
}
public static void main(String[] args) throws Exception {
long time = 0;
for (int i = 0; i < 10; i++) {
time += 250L;
HashKeyTest hk = new HashKeyTest("SPY", time);
System.out.format("%d:%10.12f\n", time, hk.random());
Thread.sleep(1);
}
}
}
- Die Lösung ist ungeeignet für die meisten Zwecke, einschließlich gaming. Es ist im wesentlichen re-instanziieren eines RNG für jeden Anruf.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sagte Sie, "ich sollte die gleiche Zufallszahl, wenn ich die Abfrage mit dem gleichen Schlüssel und auch, ich sollte bekommen eine ganz andere Nummer, wenn ich die Abfrage mit einem etwas anderen Schlüssel". Wenn ich verstehe deine Frage richtig, Sie wollen nicht eine zufällige Zahl, sondern eher so etwas wie eine kryptographische hash-code.
Sollten Sie schauen vorbei, was auch immer Daten, die Sie durch eine hash-Funktion wie SHA oder MD5. Dies gibt Ihnen etwas, das scheinbar zufällig mit Bezug auf die Eingabe, aber immer die gleichen den gleichen Eingang, und wird sehr stark variieren, auch wenn Sie Ihre Eingabe variieren nur sehr wenig.
BEARBEITEN:
Konsequent erhalten double-Werte versuchen, so etwas wie dieses (pseudo-code):
Die Idee hier ist die Verwendung des SHA-hash-Wert als Ausgangswert zu initialisieren, dein Zufallsgenerator. Das ist ziemlich viel, was Sie haben, aber ich weiß nicht, was Ihr HashBuilder produziert in Bezug auf die unterschiedlichen Werte. Also mit SHA-hashes stattdessen könnte die situation verbessern.
Sollten Sie auch berücksichtigen, dass "sehr unterschiedliche" Werte für Doppel zwischen 0 und 1 ist vielleicht nicht sofort ersichtlich.
Ich würde halt den key-hash, der sich selbst als "zufällige" Zahl. Unter der Annahme einer sinnvollen hash-Implementierung, es wird über alle Eigenschaften, die Sie erwähnt haben.
Dass ist ein etwas überraschendes Ergebnis. Ich hätte gedacht, dass ein kleiner Unterschied in den Samen führen sollte, um einen großen Unterschied in der Folge von Zufallszahlen. Auf die Reflexion, ich weiß nicht, warum ich das dachte.
Immer noch, ist es leicht zu festen!
Ist es das einfachste, vielleicht ist einfach zu lassen, die random number generator Aufwärmen ein wenig, bevor Sie es verwenden. Die bitstreams erzeugt durch die verschiedenen Samen beginnen ähnlich, aber divergieren ziemlich schnell, so einfach wegwerfen die frühen Teile des bitstreams sollte den job tun. Unmittelbar nach der Zeile, wo Sie die
Random
ist, fügen Sie diese:Oder, für mehr Divergenz:
Einen schnellen test zeigt, dass dieser bekommt eine viel breitere Auswahl von zahlen.
Andere Möglichkeit wäre die Verwendung einer
java.security.SecureRandom
wie der random number generator. Dieses macht einen besseren job, der die Erzeugung unterschiedlicher outputs von ähnlichen Eingaben. Sie und bepflanzen es mit einem byte-array; Sie produzieren könnte man sagen, etwas wie(str + time).getBytes()
.Eine weitere Möglichkeit wäre, nehmen Sie Ihre Samen, dann Hashen unter Verwendung einer kryptographischen hash wie SHA-256, verwenden Sie dann ein Teil, dass wie die Samen. Die Vermischung dauern würde, sehr ähnlich Eingänge und produzieren sehr unterschiedliche Ausgänge haben, die würden dann geben Sie entsprechend die verschiedenen zufälligen Bitstrom.
Was ich verstehe ist:
time
und ein stringstr
müssen berücksichtigt werden, um die Berechnung der Zufallszahltime
Teil.time
+str
Kombination erzeugen soll, die gleiche Zufallszahl.time
+str
Kombinationen erzeugen die gleiche Zufallszahl.Aus dem code, den Sie geschrieben, es scheint die
HashCodeBuilder()
ist nicht so empfindlich wie Sie möchten, es zu sein, dietime
.Abgesehen von dem, was andere haben vorgeschlagen, eine Idee könnte sein, ändern Sie die
time
selbst in einer konsistenten Art und Weise.Können Sie die Letzte Ziffer der
time
(dielong
Teil des Schlüssels), und verschieben Sie es irgendwo in der Mitte der Reihe. e.g, IhrhashCode()
werden kann:(Der code ist nicht gerade das verschieben der letzten Ziffer in die Mitte, sondern ist etwas ähnliches im Zusammenhang mit der Frage)
Aber das wäre irgendwie langsam. So könnten Sie transformieren es, um bit-Operatoren.
Art, wie das extrahieren der letzten 6 bits der Zeit (
time & 63l
) und setzen diese bits Weg in die front (57
ist ziemlich zufällig. Ich will nur zu bewegen, diese bits zu mehr bedeutende Positionen). Dies entspricht nicht dem "verschieben Stelle irgendwo in der Mitte" Analogie genau, aber ist ähnlich wie konzeptionell.Erhalten Sie mehr Varianz, wenn Sie extrahieren nur die letzten 5 bits (
time & 31l
). Sie könnten versuchen, verschiedene Werte. Für den code gepostet der Frage, dietime & 63l
version gibt die folgende Ausgabe zurück:die, wie erwartet, deutlich mehr Varianz für kleine änderungen in der
long
Teil des Schlüssels.hashCode
sollte den gleichen Wert für die gleiche Instanz... das ist der Punkt der Vermischung. Auch: "ich soll die Holen Sie sich die gleiche Zufallszahl, wenn ich die Abfrage mit dem gleichen key"time
ist hier der Schlüssel, es ist nicht die system-Zeit. Es ist Teil des Objekts! Ich bin nur der Bearbeitung der Op-code)time.time()
Angabe der system-Zeit.