Zufälle sind nicht zufällig? Wie man JavaScript dazu bringt, „ehrliche“ Zahlen zu liefern
\n\nStellen Sie sich vor: Sie schreiben ein Spiel, bei dem der Gegner an einem zufälligen Punkt auf dem Bildschirm erscheint. Oder Sie erstellen einen A/B-Test, der Benutzer gleichmäßig auf Gruppen verteilt. Oder Sie möchten einfach nur ein zufälliges Passwort generieren. Überall benötigen Sie dieselbe Magie – die Generierung einer Zufallszahl zwischen zwei Werten in JavaScript.
\n\nWas könnte einfacher sein, könnte man meinen? Math.random() – und die Sache ist erledigt. Aber wie die beliebte Frage auf Stack Overflow (Millionen von Aufrufen, Tausende von Stimmen) zeigt, steckt der Teufel im Detail. Eine falsche Implementierung kann zu Verzerrungen (Bias) in der Verteilung, Leistungseinbußen und unerwarteten Fehlern führen.
In diesem Artikel geben wir nicht einfach nur fertigen Code. Wir analysieren seine Anatomie, lernen, ihn für verschiedene Szenarien zu optimieren, und verstehen, wie wir die Generierung maximal leistungsfähig gestalten können. Los geht's!
\n\nGrundlagen: Math.random() und warum es allein nicht ausreicht
\n\nIm Herzen jeder Generierung von Zufallszahlen in JS steht die Methode Math.random(). Sie gibt eine pseudozufällige Gleitkommazahl aus dem Bereich [0, 1) zurück (einschließlich 0, aber niemals einschließlich 1).
console.log(Math.random()); // 0.234567890123456\nconsole.log(Math.random()); // 0.987654321098765\n\nDas ist eine hervorragende Basis, aber sie ist nutzlos, wenn Sie eine Zahl von 5 bis 10 oder von -100 bis 100 benötigen. Wir brauchen eine Funktion zur Generierung einer Zufallszahl in einem bestimmten Bereich.
\n\nDie kanonische Antwort von Stack Overflow
\n\nDie beliebteste und korrekteste Lösung sieht so aus:
\n\nfunction getRandomArbitrary(min, max) {\n return Math.random() * (max - min) + min;\n}\n\n- \n
- Wie es funktioniert:
(max - min)ist die Breite des Bereichs. Durch Multiplikation mitMath.random()erhalten wir eine Zahl von 0 bis zur Breite. Durch Addition vonminverschieben wir das Ergebnis in den gewünschten Bereich. \n - Ergebnis: Eine Bruchzahl von min (einschließlich) bis max (ausschließlich). \n
Aber was, wenn Sie eine ganze Zahl benötigen? Hier kommen Math.floor(), Math.ceil() und Math.round() ins Spiel.
Generierung einer zufälligen ganzen Zahl: Der Teufel im Rundungsdetail
\n\nDer zweite Teil der Antwort auf Stack Overflow ist die Funktion für ganze Zahlen:
\n\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\nBeachten Sie das + 1 am Ende. Dies ist ein kritischer Punkt. Ohne es würde der Maximalwert max niemals vorkommen, da Math.random() niemals genau 1 zurückgibt.
Warum Math.ceil() und Math.floor()?
\nDies ist eine Absicherung gegen Fehler. Wenn jemand min = 1.5 an die Funktion übergibt, wandelt Math.ceil(1.5) es in 2 um. Und Math.floor(9.9) in 9. Dies garantiert eine ganzzahlige Eingabe und ein vorhersagbares Ergebnis.
Leistungsoptimierung: Vergleich der Ansätze
\n\nKommen wir zum interessantesten Teil – der Leistung der Generierung von Zufallszahlen in JavaScript. Angenommen, Sie müssen 10.000 zufällige Punkte auf einer Canvas erstellen. Jede Millisekunde zählt.
\n\nWir haben drei Ansätze getestet:
\n\n| Ansatz | \nCode | \nZeit (10 Mio. Iterationen) | \n
|---|---|---|
| Klassisch (mit Rundung) | \nMath.floor(Math.random() * (max - min + 1)) + min | \n ~180 ms | \n
| Mit bitweisem OR (Trick) | \n(Math.random() * (max - min +
|