3 # Generates a random integer in a given range
4 # http://unix.stackexchange.com/questions/157250/how-to-efficiently-generate-large-uniformly-distributed-random-integers-in-bas/157837#157837
6 # computes the ceiling of log2
7 # i.e., for parameter x returns the lowest integer l such that 2**l >= x
10 while (( x
>n
&& n
>0 ))
17 # uses $RANDOM to generate an n-bit random bitstring uniformly at random
18 # (if we assume $RANDOM is uniformly distributed)
19 # takes the length n of the bitstring as parameter, n can be up to 60 bits
21 local n
=$1 rnd
=$RANDOM rnd_bitlen
=15
22 while (( rnd_bitlen
< n
))
24 rnd
=$
(( rnd
<<15|$RANDOM ))
27 echo $
(( rnd
>>(rnd_bitlen-n
) ))
30 # alternative implementation of get_n_rand_bits:
31 # uses /dev/urandom to generate an n-bit random bitstring uniformly at random
32 # (if we assume /dev/urandom is uniformly distributed)
33 # takes the length n of the bitstring as parameter, n can be up to 56 bits
34 get_n_rand_bits_alt
() {
36 local nb_bytes
=$
(( (n
+7)/8 ))
37 local rnd
=$
(od --read-bytes=$nb_bytes --address-radix=n
--format=uL
/dev
/urandom |
tr --delete " ")
38 echo $
(( rnd
>>(nb_bytes
*8-n) ))
41 # for parameter max, generates an integer in the range {0..max} uniformly at random
42 # max can be an arbitrary integer, needs not be a power of 2
45 # get number of bits needed to represent $max
46 local bitlen
=$
(log2 $
((max
+1)))
48 # could use get_n_rand_bits_alt instead if /dev/urandom is preferred over $RANDOM
49 rnd
=$
(get_n_rand_bits
$bitlen)
58 # check number of parameters
59 if (( $# != 1 && $# != 2 ))
62 Usage: $(basename $0) [min] max
64 Returns an integer distributed uniformly at random in the range {min..max}
66 (max - min) can be up to 2**60-1
71 # If we have one parameter, set min to 0 and max to $1
72 # If we have two parameters, set min to $1 and max to $2
81 # ensure that min <= max
84 echo "$(basename $0): error: min is greater than max" 1>&2
88 # need absolute value of diff since min (and also max) may be negative
89 diff=$
((max-min
)) && diff=${diff#-}
91 echo $
(( $
(rand
$diff) + min
))