Ist es möglich, mit dem Integer Random echte Zufallszahlen mit einer bestimmten Genauigkeit und in einem bestimmten Bereich zu generieren Generator $ ZUFÄLLIG? Wie können wir beispielsweise eine reelle Zahl mit einer Genauigkeit von 4 zwischen 0 und 1 generieren?
0.1234 0.0309 0.9001 0.0000 1.0000
Eine einfache Problemumgehung:
printf "%d04.%d04\n" $RANDOM $RANDOM
Kommentare
- Bitte geben Sie an, was Sie unter “ reellen Zufallszahlen . Benötigen Sie eine Quelle für Zufallszahlen, die durch Partikelzerfall erzeugt werden, oder sind Sie mit einem Pseudozufallsgenerator zufrieden? Ist Ihre Anwendung dieser Zahlen von kryptografischer oder wissenschaftlicher Bedeutung oder möchten Sie nur etwas, das “ zufällig aussieht „.
- … oder meinst du eigentlich “ float “ oder “ float Punktnummer?
- Vielen Dank für Ihren Kommentar. Ich benötige einen Pseudozufallszahlengenerator für Gleitkommazahlen basierend auf $ RANDOM.
- … für die Implementierung von meta-heuristischen Algorithmen in Bash.
Antwort
awk -v n=10 -v seed="$RANDOM" "BEGIN { srand(seed); for (i=0; i<n; ++i) printf("%.4f\n", rand()) }"
Dies gibt n
Zufallszahlen aus (zehn im Beispiel) im Bereich [0,1] mit vier Dezimalstellen. Es verwendet die Funktion rand()
in awk
(nicht im Standard awk
, sondern wird von den meisten implementiert awk
Implementierungen), die einen zufälligen Wert in diesem Bereich zurückgeben. Der Zufallszahlengenerator wird von der Shell „s $RANDOM
-Variable gesetzt.
Wenn ein awk
-Programm nur BEGIN
-Blöcke (und keine anderen Codeblöcke), awk
versucht nicht, Eingaben aus dem Standardeingabestream zu lesen.
Auf jedem OpenBSD-System (oder System mit demselben jot
-Dienstprogramm , ursprünglich in 4.2BSD), das Folgende generiert 10 Zufallszahlen wie angegeben:
jot -p 4 -r 10 0 1
Kommentare
- Wirklich genau genommen, seit der Ausgabe von
rand()
ist ein Gleitkommawert innerhalb von [0,1), es ist wahrscheinlich nicht ‚ nicht genau gleichmäßig verteilt, wenn es auf vier Dezimalstellen gerundet wird. Es wäre, wenn der Float von unendlicher Genauigkeit wäre, aber es ist nicht ‚ t: Es ist wahrscheinlich, dass ‚ aus zufälligen Bits generiert wird Es gibt also 2 ^ N verschiedene Werte und Sie werden ‚ nicht einheitlich einem Satz von 1000 Werten zugeordnet. Aber solange diese pseudozufälligen Floats genug Bits haben und Sie ‚ nichts wirklich Genaues tun, werden Sie wahrscheinlich ‚ t Beachten Sie.
Antwort
Wie in einer anderen Antwort ausgeführt, gibt es andere Dienstprogramme, die Sie zum Generieren verwenden können zufällige Zahlen. In dieser Antwort beschränke ich meine Ressourcen auf $RANDOM
und einige grundlegende arithmetische Funktionen.
Versuchen Sie für Gleitkommazahlen etwas wie
printf "%s\n" $(echo "scale=8; $RANDOM/32768" | bc )
Damit erhalten Sie die beste Genauigkeit, da $RANDOM
nur Zahlen zwischen 0 und 32767 generiert. (einschließlich 32767!) Aber ich “ Ich habe auch gegen meine Regel bezüglich der Verwendung grundlegender arithmetischer Funktionen verstoßen, indem ich bc
aufgerufen habe.
Aber bevor ich fortfahre, möchte ich zwei Punkte genauer betrachten und Bereich für Gleitkommazahlen. Danach werde ich einen Bereich von Ganzzahlen generieren (und wenn Sie Ganzzahlen generieren können, können Sie diese später teilen, um eine Dezimalzahl zu erhalten, wenn Sie die Dienstprogramme verwenden möchten, die Sie dafür bevorzugen.)
Präzision
Nach $RANDOM/32768
, seit $RANDOM
generiert Werte von 0 bis 32767, das Ergebnis von $RANDOM/32768
sind ebenfalls endlich viele Werte. Mit anderen Worten, es ist immer noch eine diskrete Zufallsvariable (und mit einem Computer werden Sie nie in der Lage sein, sich dieser Tatsache zu entziehen). In diesem Sinne können Sie mit printf
ein gewisses Maß an Präzision erreichen.
Wenn Sie eine feinere Abdeckung des Intervall könnten Sie anfangen, in Basis 32768 zu denken. Theoretisch sollte $RANDOM + $RANDOM*32768
Ihnen eine gleichmäßige Verteilung zwischen 0 und 1.073.741.823 geben. Ich bezweifle jedoch, dass die Befehlszeile mit dieser Genauigkeit sehr gut umgehen kann. Einige Punkte in Bezug auf diesen speziellen Fall:
- Die Summe zweier unabhängiger, gleichmäßig verteilter Zufallsvariablen ist im Allgemeinen nicht einheitlich. In diesem Fall sind sie zumindest theoretisch (siehe dritter Punkt).
- Denken Sie nicht, dass Sie
$RANDOM + $RANDOM*32768 = $RANDOM * ( 1 + 32768 )
vereinfachen können.Die beiden Vorkommen von$RANDOM
sind wirklich zwei verschiedene Ereignisse. - Ich weiß nicht genug darüber, wie
$RANDOM
ist Wird generiert, um zu wissen, ob ein zweimaliger Aufruf tatsächlich zwei unabhängige zufällige Ereignisse generiert.
Bereich
Betrachten wir nur $RANDOM/32768
. Wenn Sie eine Zahl in einem Bereich wünschen, z. B. [a,b)
, dann
$RANDOM/32768*(b-a) + a
landen Sie im gewünschten Bereich .
Generierung ganzzahliger Werte
Betrachten Sie zunächst die Generierung von Zufallszahlen zwischen [0,b)
wobei b
kleiner als 32768
ist. Betrachten Sie das Produkt q*b
, wobei q
der ganzzahlige Teil von 32768/b
ist. Dann können Sie eine Zufallszahl zwischen 0 und 32767 generieren, aber diejenigen wegwerfen, die größer oder gleich q*b
sind. Rufen Sie die so generierte Nummer G
an. Dann fällt G
in den Bereich von 0 bis q*b
und seine Verteilung ist gleichmäßig. Wenden Sie nun modulare Arithmetik an, um diesen Wert in den gewünschten Bereich zu bringen:
G % b
Beachten Sie, dass Sie zufällig eine Zahl wie folgt generieren:
$RANDOM % b
erstellt keine gleichmäßige Verteilung, es sei denn, b
ist zufällig einer der Teiler von 32768
.
Schreiben eines Bash-Skripts für dieses
Berechnen q*b
wie oben beschrieben klingt wie ein Schmerz. Aber es ist wirklich nicht „t. Sie können es wie folgt erhalten:
q*b = 32768 - ( 32768 % b )
In Bash können Sie dies mit
Der folgende Code generiert eine Zufallszahl im Bereich 0..b
(ohne b
) b=$1
m=$((32768 - $((32768 % $1)) )) a=$RANDOM while (( $a > $m )); do a=$RANDOM done a=$(($a % $1)) printf "$a\n"
Nachtrag
Technisch gesehen gibt es wenig Grund, mit
m=$((32768 - $((32768 % $1)) ))
zu arbeiten
a=$RANDOM while (( $a > $1 )); do a=$RANDOM done printf "$a\n"
Es ist viel mehr Arbeit, aber Computer sind schnell.
Generieren einer Ganzzahl in einem größeren Bereich
Ich werde Sie dies herausfinden lassen. Vorsicht ist geboten, und irgendwann müssen Sie die Speicherbeschränkungen des Computers bei der Verarbeitung von Rechenoperationen berücksichtigen.
Schlussbemerkung
Die akzeptierte Antwort erstellt keine einheitliche Zufallszahl über 0 bis 1.
Versuchen Sie Folgendes, um dies zu sehen.
$ for i in {1..1000}; do echo .$RANDOM; done | awk "{ a += $1 } END { print a }"
Für eine wirklich gleichmäßige Verteilung über [0,1)
sollte ein Durchschnitt nahe .
Wie Sie jedoch sehen können, wenn Sie das obige Snippet ausführen, erhalten Sie stattdessen etwas wie 314.432
oder 322.619
. Da es sich um 1000 Zahlen handelt, ist der Durchschnitt davon .322
. Der wahre Durchschnitt für diese Folge generierter Zahlen ist .316362
Sie können diesen wahren Durchschnitt mit dem Perl-Skript
Ich füge hier Ganzzahlen hinzu, um Ihnen zu zeigen, wie dieser Ansatz der Verwendung von .$RANDOM
nicht das tut, was Sie höchstwahrscheinlich wollen. Mit anderen Worten, denken Sie darüber nach, welche Ganzzahlen generiert werden und welche insgesamt fehlen. Eine große Anzahl wird übersprungen; Einige werden verdoppelt.
Antwort
Auf Systemen, auf denen die printf der Shell die -Format (bash ksh zsh usw.) und ist daher in der Lage, eine interne Basisänderung (hex -> dec) durchzuführen (einheitlich im Bereich
von 0,00003) bis 0.99997):
printf "%.5f\n" "$(printf "0x0.%04xp1" $RANDOM)"
Sie können sogar mehr Ziffern verwenden, indem Sie mehr Aufrufe an $RANDOM
(von 0.000000001 bis 0.999999999)
printf "%.9f\n" "$(printf "0x0.%08xp2" $(( ($RANDOM<<15) + $RANDOM )))"
Der interne (für die Shell) „$ RANDOM“ -Algorithmus basiert auf einem Schieberegister mit linearer Rückkopplung (LFSR). Diese sind nicht kryptografisch Sichere Pseudozufallszahlengeneratoren (CSPRNGs). Eine bessere Option ist die Verwendung von Bytes vom Gerät /dev/urandom
. Dies erfordert den Aufruf eines externen Oktal- oder Hex-Dumps.
$ printf "%.19f\n" "0x0.$(od -N 8 -An -tx1 /dev/urandom | tr -d " ")" 0.7532810412812978029 $ printf "%.19f\n" "0x0.$(hexdump -n 8 -v -e ""%02x"" /dev/urandom)" 0.9453460825607180595
Eine sehr einfache (aber ungleichmäßige) Lösung, um einen Float zu erhalten, ist:
printf "0.%04d\n" $RANDOM
Eine Möglichkeit, es im Bereich [0,1)
(ohne 1) einheitlich zu machen:
while a=$RANDOM; ((a>29999)); do :; done; printf "0.%04d\n" "$((a%10000))"
Antwort
Verwenden Sie $(( ( RANDOM % N ) + MIN ))
Ersetzen Sie N
mit MAX-Nummer und MIN mit der Mindestanzahl, die Sie generieren möchten. (N
Da MAX exklusiv ist, geben Sie N+1
ein um sowohl MAX als auch MIN zu haben).
Oder Sie können stattdessen $(shuf -i MIN-MAX -n 1)
verwenden.
von man shuf
:
-i, --input-range=LO-HI treat each number LO through HI as an input line -n, --head-count=COUNT output at most COUNT lines
Die -n 1
in shuf
bedeutet hier nur eine Zufallszahl zu generieren.
Dies generiert Zufallszahlen zwischen 0 ~ 9999 mit führenden Nullen Verwenden von printf
(im Ergebnis Nummer 1
ist exklusiv).
printf "0.%04d\n" $(( RANDOM % 1000 )) 0.0215
Kommentare
- Dies Außerdem wird im angegebenen Bereich keine echte Zufallszahl erzeugt, außer in dem Fall, in dem N ein Teiler von 32767 ist (die Obergrenze von $ RANDOM).
Antwort
Bei Bash
bc -l <<< "scale=4 ; $((RANDOM % 10000 ))/10000"
wobei 1/10000
Ihr Zufall ist Genauigkeit und 4
Ziffern Ihre Ausgabegenauigkeit
Antwort
zsh
hat eine rand48()
arithmetische Funktion (Wrapper zur erand48()
Standardfunktion) in ihrer zsh/mathfunc
Modul:
zmodload zsh/mathfunc printf "%.4f\n" $((rand48()))
Während $RANDOM
15 Bit beträgt, pseudozufällig und reproduzierbar, bash
5.1+ hat eine sicherere 32-Bit-Ganzzahl $SRANDOM
, basierend auf wirklich zufälligen Quellen, sofern verfügbar. Es unterstützt keine Gleitkomma-Arithmetik, aber Sie können sie zumindest verwenden, um den Pseudozufallsgenerator von awk
zu setzen (der ansonsten standardmäßig das sehr vorhersehbare Ergebnis von time()
):
echo "$SRANDOM" | awk " { srand($1) for (i = 0; i < 20; i++) printf "%.4f\n", rand() }"
(bedenken Sie, dass es immer noch nur 32 Bit Entropie und führt eine deterministische Pseudozufallsgenerierung basierend auf diesem Startwert durch.