Warum druckt dieser Code mit zufälligen Zeichenfolgen "Hallo Welt"?


1769

Die folgende Druckanweisung würde "Hallo Welt" drucken. Könnte jemand das erklären?

System.out.println(randomString(-229985452) + " " + randomString(-147909649));

Und randomString()sieht so aus:

public static String randomString(int i)
{
    Random ran = new Random(i);
    StringBuilder sb = new StringBuilder();
    while (true)
    {
        int k = ran.nextInt(27);
        if (k == 0)
            break;

        sb.append((char)('`' + k));
    }

    return sb.toString();
}

158
Nun, diese besonderen Samen funktionieren einfach perfekt. Zufällig ist nicht wirklich zufällig, es ist pseudozufällig.
Türknauf

341
Es funktioniert, wie andere gesagt haben, weil zufällig nicht ist. Für mich wäre eine interessantere Frage, ob die Person, die das geschrieben hat, es brutal erzwingt oder ob es eine einfache Möglichkeit gibt, vorherzusagen, welcher Zufall für die nächsten N Werte für einen bestimmten Samen erzeugt werden würde. Brute Forcing ist einfach und sollte mit moderner Hardware nicht zu lange dauern, so dass dies sicher eine praktikable Methode war. Da es statisch ist, können Sie die Suche sogar problemlos über ein Netzwerk verteilen.
jmoreno

78
Ich frage mich, wozu nin for (int n = 0; ; n++). Sie könnten for(;;)oder while(true)stattdessen verwenden!
Eng.Fouad

13
In einer wirklich zufälligen Reihenfolge wird schließlich jede mögliche Zeichenfolge angezeigt. In einer hochqualitativen Pseudozufallssequenz kann vernünftigerweise jede mögliche Zeichenfolge von Längenbits (log_s (N) - n) erwartet werden (wobei N die Anzahl der Bits im internen Zustand des PRNG und n eine kleine Zahl ist, lassen Sie uns der Einfachheit halber 8 auswählen ), um im Zyklus zu erscheinen. Dieser Code wird durch die Verwendung eines frei gewählten fest codierten Startpunkts (des Werts des Zeichen-Backticks) unterstützt, der fast die gesamten 8 Bits zurückerhält.
dmckee --- Ex-Moderator Kätzchen

13
Dies ist aus einem Beitrag, den ich vor ein paar Jahren geschrieben habe. vanillajava.blogspot.co.uk/2011/10/randomly-no-so-random.html
Peter Lawrey

Antworten:


917

Wenn eine Instanz von java.util.Randommit einem bestimmten Startparameter (in diesem Fall -229985452oder -147909649) erstellt wird, folgt sie dem Zufallszahlengenerierungsalgorithmus, der mit diesem Startwert beginnt .

Jeder, Randomder mit demselben Samen konstruiert wurde, erzeugt jedes Mal das gleiche Zahlenmuster.


8
@ Vulcan - der Javadoc sagt, dass der Samen 48 Bit ist. docs.oracle.com/javase/7/docs/api/java/util/Random.html . Außerdem sind die tatsächlichen Startwerte 32-Bit-Werte.
Stephen C

80
Jedes Element der Zufallszahlenfolge wird modulo 27 genommen, und es gibt 6 Elemente in jedem von "hello\0"und "world\0". Wenn Sie von einem wirklich zufälligen Generator ausgehen würden, wäre die Wahrscheinlichkeit 1 zu 27 ^ 6 (387.420.489), die gesuchte Sequenz zu erhalten - also ziemlich beeindruckend, aber nicht ganz umwerfend!
Russell Borogove

17
@RussellBorogove: Aber mit diesen Gewinnchancen und 2 ^ 64 möglichen Samen gibt es erwartete 47,6 Milliarden Samenwerte, die diese Sequenz ergeben. Es geht nur darum, einen zu finden.
dan04

8
@ dan04 - Ich war nicht bereit, diese Schätzung vorzunehmen; Abhängig von der Implementierung des PRNG entspricht die Größe des Startworts möglicherweise nicht der Größe des Status, und die Sequenzpfade sind möglicherweise nicht gleichmäßig verteilt. Trotzdem stehen die Chancen auf jeden Fall gut, und wenn Sie kein Paar finden konnten, können Sie es erneut mit einem anderen Gehäuse ( "Hello" "World") versuchen oder 122-kanstelle von 96+koder ...
Russell Borogove

7
@ ThorbjørnRavnAndersen Der Javadoc gibt an, dass "bestimmte Algorithmen für die Klasse Random angegeben werden. Java-Implementierungen müssen alle hier gezeigten Algorithmen für die Klasse Random verwenden, um die absolute Portabilität des Java-Codes zu gewährleisten."
FThompson

1137

Die anderen Antworten erklären warum, aber hier ist wie.

Gegeben eine Instanz von Random:

Random r = new Random(-229985452)

Die ersten 6 Zahlen, die r.nextInt(27)generiert werden , sind:

8
5
12
12
15
0

und die ersten 6 Zahlen, r.nextInt(27)die gegeben werden, Random r = new Random(-147909649)sind:

23
15
18
12
4
0

Fügen Sie dann einfach diese Zahlen zur ganzzahligen Darstellung des Zeichens hinzu `(96):

8  + 96 = 104 --> h
5  + 96 = 101 --> e
12 + 96 = 108 --> l
12 + 96 = 108 --> l
15 + 96 = 111 --> o

23 + 96 = 119 --> w
15 + 96 = 111 --> o
18 + 96 = 114 --> r
12 + 96 = 108 --> l
4  + 96 = 100 --> d

48
Pedantisch, gibt new Random(-229985452).nextInt(27)immer 8 zurück.
user253751

1
@immibis warum? Ich meine, Random () sollte jedes Mal eine Zufallszahl zurückgeben, keine festgelegte Anzahl?
Roottraveller

5
@rootTraveller Gibt zunächst new Random()überhaupt keine Nummer zurück.
user253751

2
Gibt es eine Möglichkeit, diese Samen zu berechnen? Es muss eine Logik geben ... oder ist es nur rohe Gewalt?
Sohit Gore

2
@SohitGore Da Javas Standard Randomnicht kryptografisch sicher ist (ich bin mir ziemlich sicher, dass es sich um einen Mersenne Twister handelt, zitiere mich aber nicht dazu), ist es wahrscheinlich möglich, von "Ich möchte diese Zahlen" bis "Dies ist die" rückwärts zu arbeiten Samen würde ich verwenden ". Ich habe etwas Ähnliches mit dem Standard-C-Linearkongruenzgenerator gemacht.
Fund Monica Klage

280

Ich lasse es einfach hier. Wer viel (CPU-) Zeit übrig hat, kann gerne experimentieren :) Wenn Sie einige Fork-Join-Fu beherrschen, damit dieses Ding alle CPU-Kerne verbrennt (nur Threads sind langweilig, oder?), Teilen Sie dies bitte mit dein Code. Ich würde es sehr begrüßen.

public static void main(String[] args) {
    long time = System.currentTimeMillis();
    generate("stack");
    generate("over");
    generate("flow");
    generate("rulez");

    System.out.println("Took " + (System.currentTimeMillis() - time) + " ms");
}

private static void generate(String goal) {
    long[] seed = generateSeed(goal, Long.MIN_VALUE, Long.MAX_VALUE);
    System.out.println(seed[0]);
    System.out.println(randomString(seed[0], (char) seed[1]));
}

public static long[] generateSeed(String goal, long start, long finish) {
    char[] input = goal.toCharArray();
    char[] pool = new char[input.length];
    label:
    for (long seed = start; seed < finish; seed++) {
        Random random = new Random(seed);

        for (int i = 0; i < input.length; i++)
            pool[i] = (char) random.nextInt(27);

        if (random.nextInt(27) == 0) {
            int base = input[0] - pool[0];
            for (int i = 1; i < input.length; i++) {
                if (input[i] - pool[i] != base)
                    continue label;
            }
            return new long[]{seed, base};
        }

    }

    throw new NoSuchElementException("Sorry :/");
}

public static String randomString(long i, char base) {
    System.out.println("Using base: '" + base + "'");
    Random ran = new Random(i);
    StringBuilder sb = new StringBuilder();
    for (int n = 0; ; n++) {
        int k = ran.nextInt(27);
        if (k == 0)
            break;

        sb.append((char) (base + k));
    }

    return sb.toString();
}

Ausgabe:

-9223372036808280701
Using base: 'Z'
stack
-9223372036853943469
Using base: 'b'
over
-9223372036852834412
Using base: 'e'
flow
-9223372036838149518
Using base: 'd'
rulez
Took 7087 ms

24
@OneTwoThree nextInt(27)bedeutet innerhalb des Bereichs [0, 26].
Eng.Fouad

30
@Vulcan Die meisten Samen liegen sehr nahe am Maximalwert, genau wie wenn Sie Zufallszahlen zwischen 1 und 1000 auswählen, haben die meisten Zahlen, die Sie am Ende auswählen, drei Ziffern. Es ist nicht überraschend, wenn Sie darüber nachdenken :)
Thomas

18
@Vulcan Wenn Sie rechnen, werden Sie feststellen, dass sie ungefähr so ​​nahe am Maximalwert wie bei Null liegen (ich nehme an, der Startwert wird im Generierungscode als vorzeichenlos interpretiert). Da die Anzahl der Ziffern jedoch nur logarithmisch mit dem tatsächlichen Wert wächst, sieht die Zahl sehr genau aus, wenn dies nicht der Fall ist.
Thomas

10
Gute Antwort. Und für Bonuspunkte können Sie einen Startwert finden, der einen Zufall initialisiert, der die Folge von 4 Startwerten erzeugt, die für die Initialisierung der endgültigen Zufälle erforderlich sind?
Marek

13
@Marek: Ich glaube nicht, dass Götter des Pseudozufalls ein solches Verhalten gutheißen würden.
Denis Tulskiy

254

Alle hier haben großartige Arbeit geleistet, um zu erklären, wie der Code funktioniert, und um zu zeigen, wie Sie Ihre eigenen Beispiele erstellen können. Hier ist jedoch eine informationstheoretische Antwort, die zeigt, warum wir vernünftigerweise erwarten können, dass es eine Lösung gibt, die die Brute-Force-Suche irgendwann finden wird.

Die 26 verschiedenen Kleinbuchstaben bilden unser Alphabet Σ. Um Wörter unterschiedlicher Länge zu generieren, fügen wir ein Terminatorsymbol hinzu , um ein erweitertes Alphabet zu erhalten Σ' := Σ ∪ {⊥}.

Sei αein Symbol und X eine gleichmäßig verteilte Zufallsvariable über Σ'. Die Wahrscheinlichkeit, dieses Symbol zu erhalten, P(X = α)und sein Informationsgehalt I(α)sind gegeben durch:

P (X = α) = 1 / | Σ '| = 1/27

I (α) = -log₂ [P (X = α)] = -log₂ (1/27) = log₂ (27)

Für ein Wort ω ∈ Σ*und sein ⊥-terminiertes Gegenstück ω' := ω · ⊥ ∈ (Σ')*haben wir

I (ω): = I (ω ') = | ω' | * log₂ (27) = (| ω | + 1) * log₂ (27)

Da der Pseudozufallszahlengenerator (PRNG) mit einem 32-Bit-Startwert initialisiert wird, können wir die meisten Wörter mit einer Länge von bis zu erwarten

λ = Boden [32 / log₂ (27)] - 1 = 5

von mindestens einem Samen erzeugt werden. Selbst wenn wir nach einem 6-stelligen Wort suchen würden, wären wir in 41,06% der Fälle immer noch erfolgreich. Nicht zu schäbig.

Bei 7 Buchstaben sehen wir näher an 1,52%, aber ich hatte das nicht bemerkt, bevor ich es ausprobiert habe:

#include <iostream>
#include <random>

int main()
{
    std::mt19937 rng(631647094);
    std::uniform_int_distribution<char> dist('a', 'z' + 1);

    char alpha;
    while ((alpha = dist(rng)) != 'z' + 1)
    {
        std::cout << alpha;
    }
}

Siehe die Ausgabe: http://ideone.com/JRGb3l


Meine Informationstheorie ist etwas schwach, aber ich liebe diesen Beweis. Kann mir jemand die Lambda-Linie erklären, klar, dass wir den Informationsgehalt von einem zum anderen teilen, aber warum gibt uns dies unsere Wortlänge? Wie gesagt, ich bin ein bisschen verrostet, also entschuldige ich mich dafür, dass ich das Offensichtliche gefragt habe (NB, das hat etwas mit dem Shannon-Limit zu tun - von der Code-Ausgabe)
Mike HR

1
@ MikeH-R Die Lambda-Linie ist die I(⍵)neu geordnete Gleichung. I(⍵)ist 32 (Bits) und |⍵|stellt sich als 5 (Symbole) heraus.
Iceman

67

Ich habe ein schnelles Programm geschrieben, um diese Samen zu finden:

import java.lang.*;
import java.util.*;
import java.io.*;

public class RandomWords {
    public static void main (String[] args) {
        Set<String> wordSet = new HashSet<String>();
        String fileName = (args.length > 0 ? args[0] : "/usr/share/dict/words");
        readWordMap(wordSet, fileName);
        System.err.println(wordSet.size() + " words read.");
        findRandomWords(wordSet);
    }

    private static void readWordMap (Set<String> wordSet, String fileName) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(fileName));
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim().toLowerCase();
                if (isLowerAlpha(line)) wordSet.add(line);
            }
        }
        catch (IOException e) {
            System.err.println("Error reading from " + fileName + ": " + e);
        }
    }

    private static boolean isLowerAlpha (String word) {
        char[] c = word.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] < 'a' || c[i] > 'z') return false;
        }
        return true;
    }

    private static void findRandomWords (Set<String> wordSet) {
        char[] c = new char[256];
        Random r = new Random();
        for (long seed0 = 0; seed0 >= 0; seed0++) {
            for (int sign = -1; sign <= 1; sign += 2) {
                long seed = seed0 * sign;
                r.setSeed(seed);
                int i;
                for (i = 0; i < c.length; i++) {
                    int n = r.nextInt(27);
                    if (n == 0) break;
                    c[i] = (char)((int)'a' + n - 1);
                }
                String s = new String(c, 0, i);
                if (wordSet.contains(s)) {
                    System.out.println(s + ": " + seed);
                    wordSet.remove(s);
                }
            }
        }
    }
}

Ich habe es jetzt im Hintergrund laufen lassen, aber es hat bereits genug Wörter für ein klassisches Pangram gefunden:

import java.lang.*;
import java.util.*;

public class RandomWordsTest {
    public static void main (String[] args) {
        long[] a = {-73, -157512326, -112386651, 71425, -104434815,
                    -128911, -88019, -7691161, 1115727};
        for (int i = 0; i < a.length; i++) {
            Random r = new Random(a[i]);
            StringBuilder sb = new StringBuilder();
            int n;
            while ((n = r.nextInt(27)) > 0) sb.append((char)('`' + n));
            System.out.println(sb);
        }
    }
}

( Demo auf ideone. )

Ps. -727295876, -128911, -1611659, -235516779.


35

Ich war fasziniert davon, ich habe diesen Zufallswortgenerator auf einer Wörterbuchwortliste ausgeführt. Bereich: Integer.MIN_VALUE bis Integer.MAX_VALUE

Ich habe 15131 Treffer.

int[] arrInt = {-2146926310, -1885533740, -274140519, 
                -2145247212, -1845077092, -2143584283,
                -2147483454, -2138225126, -2147375969};

for(int seed : arrInt){
    System.out.print(randomString(seed) + " ");
}

Druckt

the quick browny fox jumps over a lazy dog 

7
Sie haben meinen Tag Mann gemacht: DI hat es mit Long.Min / Max versucht und nach Namen meiner Kollegen gesucht und nur Peter gefunden: (Peter 4611686018451441623 Peter 24053719 Peter -4611686018403334185 Peter -9223372036830722089 Peter -4611686017906248127 Peter-3611607 4611686017645756173 Peter 781631731 Peter 4611686019209019635 Peter -9223372036073144077 Peter -4611686017420317288 Peter 1007070616 Peter -9223372035847705192)
Marcel

25

Die meisten Zufallszahlengeneratoren sind tatsächlich "pseudozufällig". Sie sind lineare kongruente Generatoren oder LCGs ( http://en.wikipedia.org/wiki/Linear_congruential_generator )

LCGs sind bei einem festen Startwert ziemlich vorhersehbar. Verwenden Sie grundsätzlich einen Startwert, der Ihnen Ihren ersten Buchstaben gibt, und schreiben Sie dann eine App, die weiterhin das nächste int (char) generiert, bis Sie den nächsten Buchstaben in Ihrer Zielzeichenfolge treffen, und notieren Sie, wie oft Sie die LCG aufrufen mussten. Fahren Sie fort, bis Sie jeden einzelnen Buchstaben generiert haben.


3
Was ist ein Beispiel für einen Nicht-Pseudo-Zufallszahlengenerator
chiliNUT

1
@chiliNUT Solche Generatoren sind externe Geräte. Eine elektronische Lampe. Oder schlecht geschriebenes Bit, das 0 oder 1 gelesen wird. Sie können keinen reinen digitalen Generator für Zufallszahlen erstellen. Digitale Algorithmen sind NICHT zufällig, sie sind absolut präzise.
Gangnus

@chiliNUT Viele Betriebssysteme sammeln Entropie . Beispielsweise können Sie unter Linux das /dev/urandomGerät verwenden, um zufällige Daten zu lesen. Dies ist jedoch eine knappe Ressource. Daher werden solche zufälligen Daten normalerweise verwendet, um PRNGs zu setzen.
Adrian W

@AdrianW Wikipedia sagt, urandomist immer noch pseudozufällig en.wikipedia.org/wiki//dev/random
chiliNUT

1
Ja, aber es ist kryptografisch sicher, was bedeutet, dass man keine Brute-Force-Angriffe ausführen kann (um den Keim für die "zufällige" Sequenz "Hallo Welt" zu finden), aus der zufällige Sequenzen erstellt wurden /dev/random. In dem oben zitierten Artikel heißt es, dass der Linux-Kernel Entropie aus Tastatur-Timings, Mausbewegungen und IDE-Timings generiert und die zufälligen Zeichendaten über die speziellen Dateien / dev / random und / dev / urandom anderen Betriebssystemprozessen zur Verfügung stellt. Das lässt mich glauben, dass es wirklich zufällig ist. Vielleicht ist das nicht ganz richtig. Enthält aber /dev/randomzumindest etwas Entropie.
Adrian W

23

Da Multithreading mit Java sehr einfach ist, finden Sie hier eine Variante, die mit allen verfügbaren Kernen nach einem Startwert sucht: http://ideone.com/ROhmTA

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class SeedFinder {

  static class SearchTask implements Callable<Long> {

    private final char[] goal;
    private final long start, step;

    public SearchTask(final String goal, final long offset, final long step) {
      final char[] goalAsArray = goal.toCharArray();
      this.goal = new char[goalAsArray.length + 1];
      System.arraycopy(goalAsArray, 0, this.goal, 0, goalAsArray.length);
      this.start = Long.MIN_VALUE + offset;
      this.step = step;
    }

    @Override
    public Long call() throws Exception {
      final long LIMIT = Long.MAX_VALUE - this.step;
      final Random random = new Random();
      int position, rnd;
      long seed = this.start;

      while ((Thread.interrupted() == false) && (seed < LIMIT)) {
        random.setSeed(seed);
        position = 0;
        rnd = random.nextInt(27);
        while (((rnd == 0) && (this.goal[position] == 0))
                || ((char) ('`' + rnd) == this.goal[position])) {
          ++position;
          if (position == this.goal.length) {
            return seed;
          }
          rnd = random.nextInt(27);
        }
        seed += this.step;
      }

      throw new Exception("No match found");
    }
  }

  public static void main(String[] args) {
    final String GOAL = "hello".toLowerCase();
    final int NUM_CORES = Runtime.getRuntime().availableProcessors();

    final ArrayList<SearchTask> tasks = new ArrayList<>(NUM_CORES);
    for (int i = 0; i < NUM_CORES; ++i) {
      tasks.add(new SearchTask(GOAL, i, NUM_CORES));
    }

    final ExecutorService executor = Executors.newFixedThreadPool(NUM_CORES, new ThreadFactory() {

      @Override
      public Thread newThread(Runnable r) {
        final Thread result = new Thread(r);
        result.setPriority(Thread.MIN_PRIORITY); // make sure we do not block more important tasks
        result.setDaemon(false);
        return result;
      }
    });
    try {
      final Long result = executor.invokeAny(tasks);
      System.out.println("Seed for \"" + GOAL + "\" found: " + result);
    } catch (Exception ex) {
      System.err.println("Calculation failed: " + ex);
    } finally {
      executor.shutdownNow();
    }
  }
}

Um Java Noob wie mich zu haben, müssen Sie die Ausgabenummer mit dem Suffix versehen Lund den Argumenttyp in ändern long, dh randomString(long i)um herumzuspielen. :)
Obst

21

Random gibt immer die gleiche Sequenz zurück. Es wird zum Mischen von Arrays und anderen Operationen als Permutationen verwendet.

Um verschiedene Sequenzen zu erhalten, muss die Sequenz an einer Position initialisiert werden, die als "Startwert" bezeichnet wird.

Das randomSting erhält die Zufallszahl an der i-Position (seed = -229985452) der "zufälligen" Sequenz. Verwendet dann den ASCII- Code für die nächsten 27 Zeichen in der Sequenz nach der Startposition, bis dieser Wert gleich 0 ist. Dies gibt das "Hallo" zurück. Die gleiche Operation wird für "Welt" durchgeführt.

Ich denke, dass der Code für keine anderen Wörter funktioniert hat. Der Typ, der programmiert hat und die zufällige Reihenfolge sehr gut kennt.

Es ist sehr toller Geek-Code!


10
Ich bezweifle, dass er "die Zufallssequenz sehr gut kennt". Wahrscheinlicher ist, dass er nur Milliarden möglicher Samen ausprobiert hat, bis er einen gefunden hat, der funktioniert.
dan04

24
@ dan04 Echte Programmierer verwenden nicht nur das PRNG, sie erinnern sich auswendig an die gesamte Periode und zählen die Werte nach Bedarf auf.
Thomas

1
"Random gibt immer die gleiche Sequenz zurück" - setzen Sie () nach Random oder zeigen Sie es als Code an. Ansonsten ist der Satz falsch.
Gangnus

14

Das Prinzip ist, dass die Zufallsklasse, die mit demselben Startwert erstellt wurde, jedes Mal dasselbe Zahlenmuster generiert.


12

Aus der Antwort von Denis Tulskiy abgeleitet , erzeugt diese Methode den Samen.

public static long generateSeed(String goal, long start, long finish) {
    char[] input = goal.toCharArray();
    char[] pool = new char[input.length];
    label:
        for (long seed = start; seed < finish; seed++) {
            Random random = new Random(seed);

            for (int i = 0; i < input.length; i++)
                pool[i] = (char) (random.nextInt(27)+'`');

            if (random.nextInt(27) == 0) {
                for (int i = 0; i < input.length; i++) {
                    if (input[i] != pool[i])
                        continue label;
                }
                return seed;
            }

        }

    throw new NoSuchElementException("Sorry :/");
}

10

In den Java-Dokumenten ist dies eine beabsichtigte Funktion, wenn ein Startwert für die Random-Klasse angegeben wird.

Wenn zwei Instanzen von Random mit demselben Startwert erstellt werden und für jeden dieselbe Sequenz von Methodenaufrufen ausgeführt wird, werden identische Zahlenfolgen generiert und zurückgegeben. Um diese Eigenschaft zu gewährleisten, werden bestimmte Algorithmen für die Klasse Random angegeben. Java-Implementierungen müssen alle hier gezeigten Algorithmen für die Klasse Random verwenden, um die absolute Portabilität von Java-Code zu gewährleisten.

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html

Seltsamerweise würden Sie denken, dass es implizite Sicherheitsprobleme gibt, wenn vorhersehbare Zufallszahlen vorliegen.


3
Aus diesem Grund setzt der Standardkonstruktor von Random"den Startwert des Zufallszahlengenerators auf einen Wert, der sich sehr wahrscheinlich von jedem anderen Aufruf dieses Konstruktors unterscheidet" ( javadoc ). In der aktuellen Implementierung ist dies eine Kombination aus der aktuellen Zeit und einem Zähler.
Martin

Tatsächlich. Vermutlich gibt es dann praktische Anwendungsfälle zur Angabe des Ausgangswertes. Ich denke, das ist das Funktionsprinzip dieser pseudozufälligen Schlüsselanhänger, die Sie bekommen können (RSA-
Schlüsselanhänger

4
@ deed02392 Natürlich gibt es praktische Anwendungsfälle für die Angabe eines Startwerts. Wenn Sie Daten simulieren, um einen Monte-Carlo-Ansatz zur Lösung eines Problems zu verwenden, ist es eine gute Sache, Ihre Ergebnisse reproduzieren zu können. Das Setzen eines ersten Startwerts ist der einfachste Weg, dies zu tun.
Dason


3

Hier ist eine kleine Verbesserung für Denis Tulskiy Antwort . Es halbiert die Zeit

public static long[] generateSeed(String goal, long start, long finish) {
    char[] input = goal.toCharArray();

    int[] dif = new int[input.length - 1];
    for (int i = 1; i < input.length; i++) {
        dif[i - 1] = input[i] - input[i - 1];
    }

    mainLoop:
    for (long seed = start; seed < finish; seed++) {
        Random random = new Random(seed);
        int lastChar = random.nextInt(27);
        int base = input[0] - lastChar;
        for (int d : dif) {
            int nextChar = random.nextInt(27);
            if (nextChar - lastChar != d) {
                continue mainLoop;
            }
            lastChar = nextChar;
        }
        if(random.nextInt(27) == 0){
            return new long[]{seed, base};
        }
    }

    throw new NoSuchElementException("Sorry :/");
}

1

Es geht nur um den Input Seed . Gleicher Samen liefert immer die gleichen Ergebnisse. Auch wenn Sie Ihr Programm immer wieder neu ausführen, ist es die gleiche Ausgabe.

public static void main(String[] args) {

    randomString(-229985452);
    System.out.println("------------");
    randomString(-229985452);

}

private static void randomString(int i) {
    Random ran = new Random(i);
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());

}

Ausgabe

-755142161
-1073255141
-369383326
1592674620
-1524828502
------------
-755142161
-1073255141
-369383326
1592674620
-1524828502
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.