È possibile generare numeri casuali reali con una precisione specifica e in un intervallo specifico utilizzando Integer Random Generatore $ RANDOM? Ad esempio, come possiamo generare un numero reale con una precisione 4 compresa tra 0 e 1?
0.1234 0.0309 0.9001 0.0000 1.0000 Una semplice soluzione:
printf "%d04.%d04\n" $RANDOM $RANDOM Commenti
- Specifica cosa intendi per ” numeri casuali reali “. Stai richiedendo una fonte di numeri casuali generati da qualcosa come il decadimento delle particelle o sarai soddisfatto di un generatore pseudo-casuale? La tua applicazione di questi numeri ha un significato crittografico o scientifico o desideri semplicemente qualcosa che ” sembri casuale “.
- … o intendi effettivamente ” float ” o ” floating numero punto?
- Grazie per il commento. Ho bisogno di un generatore di numeri pseudo casuali per numeri in virgola mobile basati su $ RANDOM.
- … per implementare algoritmi meta euristici in bash.
Risposta
awk -v n=10 -v seed="$RANDOM" "BEGIN { srand(seed); for (i=0; i<n; ++i) printf("%.4f\n", rand()) }"  Questo produrrà n numeri casuali (dieci nellesempio) nellintervallo [0,1) con quattro cifre decimali. Utilizza la funzione rand() in awk (non nello standard awk ma implementata dai più comuni awk implementazioni) che restituisce un valore casuale in quellintervallo. Il generatore di numeri casuali è seminato dalla variabile $RANDOM della shell. 
 Quando un programma awk ha solo BEGIN (e nessun altro blocco di codice), awk non tenterà di leggere linput dal suo flusso di input standard. 
 Su qualsiasi sistema OpenBSD (o sistema che ha la stessa  jot utility , originariamente in 4.2BSD), quanto segue genererà 10 numeri casuali come specificato: 
jot -p 4 -r 10 0 1 Commenti
-  In senso stretto, poiché loutput di rand()è un float allinterno di [0,1), probabilmente non è ‘ t distribuito esattamente in modo uniforme quando arrotondato a quattro cifre decimali. Lo sarebbe, se il float fosse di precisione infinita, ma non è ‘ t: è probabile che ‘ sia generato da bit casuali , quindi ci sono 2 ^ N valori diversi, e non ‘ t mappano uniformemente su un insieme di 1000 valori. Ma fino a quando quei float pseudo-casuali hanno abbastanza bit e ‘ non stai facendo nulla di veramente preciso, probabilmente hai vinto ‘ t avviso.
Risposta
 Come sottolineato in unaltra risposta, ci sono altre utilità che puoi utilizzare per generare numeri casuali. In questa risposta, limito le mie risorse a $RANDOM e ad alcune funzioni aritmetiche di base. 
Per i numeri in virgola mobile, prova qualcosa come
printf "%s\n" $(echo "scale=8; $RANDOM/32768" | bc )  In questo modo otterrai la migliore precisione perché $RANDOM genera solo numeri compresi tra 0 e 32767. (incluso 32767!) Ma io ” ho anche infranto la mia regola sulluso delle funzioni aritmetiche di base invocando bc. 
Ma prima di andare avanti, vorrei esaminare due problemi precisione e intervallo per i numeri in virgola mobile. Dopodiché, esaminerò la generazione di un intervallo di numeri interi (e se puoi generare numeri interi, puoi dividerli in seguito per ottenere un decimale se desideri utilizzare le utilità che preferisci per farlo.)
Precisione
 Adottando lapproccio di $RANDOM/32768, da $RANDOM genera valori da 0 a 32767, il risultato di $RANDOM/32768 sarà similmente un numero finito di valori. In altre parole, è ancora una variabile casuale discreta (e con un computer non sarai mai in grado di sfuggire a questo fatto). Con questo in mente, puoi ottenere un certo grado di  precisione  utilizzando printf. 
 Se desideri una copertura più fine del intervallo, potresti iniziare a pensare in base 32768. Quindi, in teoria $RANDOM + $RANDOM*32768 dovrebbe darti una distribuzione uniforme tra 0 e 1.073.741.823. Ma, dubito che la riga di comando gestirà molto bene questa precisione. Un paio di punti relativi a questo caso particolare: 
- La somma di due variabili casuali indipendenti e distribuite uniformemente non è generalmente uniforme. In questo caso, almeno in teoria (vedi terzo punto), lo sono.
-  Non pensare di poter semplificare $RANDOM + $RANDOM*32768 = $RANDOM * ( 1 + 32768 ).Le due occorrenze di$RANDOMsono in realtà due eventi diversi.
-  Non ne so abbastanza di come sia $RANDOMgenerato per sapere se chiamarlo due volte in questo modo genererà veramente due eventi casuali indipendenti.
Intervallo
 Consideriamo solo $RANDOM/32768. Se desideri un numero in un intervallo, dì [a,b), quindi 
$RANDOM/32768*(b-a) + a ti porterà nellintervallo desiderato .
Generazione di valori interi
 Innanzitutto, considera la possibilità di generare numeri casuali tra [0,b) dove b è minore di 32768. Considera il prodotto q*b, dove q è la parte intera di 32768/b. Quindi quello che puoi fare è generare un numero casuale compreso tra 0 e 32767, ma eliminare quelli che sono maggiori o uguali a q*b. Chiama il numero così generato G. Quindi G ricadrà nellintervallo da 0 a q*b e la sua distribuzione sarà uniforme. Ora, applica laritmetica modulare per ottenere questo valore ridotto nellintervallo desiderato: 
G % b Nota, generando casualmente un numero come segue
$RANDOM % b  non creerà una distribuzione uniforme, a meno che b non sia uno dei divisori di 32768. 
Scrittura di uno script bash per questo
 Calcolo q*b come descritto sopra suona come un dolore. Ma in realtà non è “t. Puoi ottenerlo come segue: 
q*b = 32768 - ( 32768 % b ) In Bash, puoi ottenerlo con
$((32768 - $((32768 % b)) ))  Il seguente codice genererà un numero casuale nellintervallo 0..b (non comprensivo di b) . b=$1 
m=$((32768 - $((32768 % $1)) )) a=$RANDOM while (( $a > $m )); do a=$RANDOM done a=$(($a % $1)) printf "$a\n" Addendum
Tecnicamente, ci sono pochi motivi per lavorare con
m=$((32768 - $((32768 % $1)) )) Quanto segue porterà a termine la stessa cosa
a=$RANDOM while (( $a > $1 )); do a=$RANDOM done printf "$a\n" È “molto più faticoso, ma i computer sono veloci.
Generazione di un numero intero in un intervallo più ampio
Ti lascio capire. È necessario prestare attenzione e ad un certo punto dovrai prendere in considerazione i limiti di memoria del computer nella gestione delle operazioni aritmetiche.
Nota finale
La risposta accettata non creerà un numero casuale uniformemente compreso tra 0 e 1.
Per vedere questo, prova quanto segue
$ for i in {1..1000}; do echo .$RANDOM; done | awk "{ a += $1 } END { print a }"  Per una distribuzione veramente uniforme su [0,1) dovresti vedere una media vicina a 0.500. 
 Ma come puoi vedere eseguendo lo snippet sopra, otterrai invece qualcosa come 314.432 o 322.619. Poiché sono 1000 numeri, la media è .322. La media reale per questa sequenza di numeri generati è .316362 
Puoi ottenere questa media reale utilizzando lo script perl
 perl -e "{ $i=0; $s=0; while ( $i<=32767 ) { $j = sprintf "%.5f", ".$i"; $j =~ s/^0\.//; print "$j\n"; $s += $j; $i++ }; printf "%.5f\n", $s/32767; }"  Sto aggiungendo degli interi qui per aiutarti a vedere come questo approccio di usare .$RANDOM non sta facendo quello che molto probabilmente vuoi che faccia. In altre parole, pensa a quali numeri interi vengono generati e quali vengono persi del tutto. Un numero abbastanza elevato viene ignorato; alcuni sono raddoppiati. 
Risposta
 Su sistemi in cui printf di shell è in grado di capire il %a (bash ksh zsh, ecc.) e quindi è in grado di eseguire un cambio di base interno (hex -> dec) (uniforme in [0,1) range da 0,00003 a 0.99997): 
printf "%.5f\n" "$(printf "0x0.%04xp1" $RANDOM)"  potresti persino utilizzare più cifre combinando più chiamate a $RANDOM (da 0.000000001 a 0.999999999) 
printf "%.9f\n" "$(printf "0x0.%08xp2" $(( ($RANDOM<<15) + $RANDOM )))"  Lalgoritmo “$ RANDOM” interno (alla shell) si basa su un registro a scorrimento a feedback lineare (LFSR). Non sono crittograficamente Generatori di numeri pseudo casuali sicuri (CSPRNG). Unopzione migliore è utilizzare i byte dal dispositivo /dev/urandom. Ciò richiederà la chiamata a ottale esterno o dump esadecimale.
$ 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 Una soluzione molto semplice (ma non uniforme) per ottenere un float è:
printf "0.%04d\n" $RANDOM  Un modo per renderlo uniforme nellintervallo [0,1) (escluso 1): 
while a=$RANDOM; ((a>29999)); do :; done; printf "0.%04d\n" "$((a%10000))" Risposta
 Utilizza $(( ( RANDOM % N ) + MIN )) 
 Sostituisci N con il numero MAX e MIN con il numero minimo che desideri generare. (N poiché MAX è esclusivo, metti N+1 per avere entrambi MAX e MIN inclusi). 
 Oppure puoi utilizzare $(shuf -i MIN-MAX -n 1). 
 da  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  Il -n 1 in shuf qui significa generare solo un numero casuale. 
 Questo genererà numeri casuali compresi tra  0 ~ 9999  con zeri iniziali utilizzando printf (nel risultato, numero  1 
è esclusivo).
printf "0.%04d\n" $(( RANDOM % 1000 )) 0.0215 Commenti
- Questo inoltre non produrrà un vero numero casuale nellintervallo dato tranne nel caso in cui N è un divisore di 32767 (il limite superiore di $ RANDOM).
Risposta
On bash
bc -l <<< "scale=4 ; $((RANDOM % 10000 ))/10000"  dove 1/10000 è il tuo casuale precisione e 4 cifre la precisione delloutput 
Risposta
 zsh ha una rand48() funzione aritmetica (wrapper della erand48() funzione standard) nella sua zsh/mathfunc modulo: 
zmodload zsh/mathfunc printf "%.4f\n" $((rand48()))  Mentre $RANDOM è di 15 bit, pseudo-casuale e riproducibile, bash 5.1+ ha un numero intero a 32 bit più sicuro $SRANDOM, basato su fonti veramente casuali, ove disponibili. Non supporta laritmetica in virgola mobile, ma almeno puoi usarlo per seminare lo pseudo generatore di awk “(che altrimenti per impostazione predefinita usa il risultato molto prevedibile di time()): 
echo "$SRANDOM" | awk " { srand($1) for (i = 0; i < 20; i++) printf "%.4f\n", rand() }"  (tieni presente che sono ancora solo 32 bit di entropia e awk genera una generazione pseudo-casuale deterministica basata su quel seme)