How can I generate equally distributed random numbers in a range and with p.e, 2 or 5 decimal places in bash without to use AWK or bc ?
Bash usually only supports whole numbers. However, numbers with decimal places can be used in bash, e.g. with the command sleep: sleep 1.23456 # sleep time in s
Given is the following example, which can generate with bash in a range from 0 to 10, equally distributed random numbers without decimal places.
ug_rnd=0
og_rnd=10
rnd="$((0x$(dd if=/dev/urandom of=/dev/stdout bs=4 count=1 status=none | xxd -p)))"
my_rnd=$((rnd%(og_rnd-ug_rnd 1) ug_rnd));
echo "$my_rnd"
sleep "$my_rnd"
CodePudding user response:
Assume you're currently generating random numbers between 0
and 10
and you want to add 2 decimal places.
Consider generating random numbers between 0
and 1000
(10 * 10^2
), split the result into 2x chunks and then piece together with a decimal.
A rough example:
NOTE: Added Kamilcuk's comment re: using printf
to take care of left padding numbers with 0's
$ x=735 # assume this is our random number (between 0 and 1000)
$ printf -v newx "%d.d" "$((x/100))" "$((x0))"
$ echo "${newx}"
7.35
$ time sleep "${newx}"
real 0m7.375s
user 0m0.000s
sys 0m0.015s
If OP wants 4 decimal places then generate a random number between 0
and 100000
(10 x 10^4
), and replace the 100
entries (in the newx
split-n-piece-together operation) with 10000
.
Shouldn't be too hard to add some logic to current code to figure out the multiplier (10^<number_of_decimals>
), set og_rnd=$((10*<multiplier))
, and replace 100
with the <multiplier>
variable in the split-n-piece-together operation.
CodePudding user response:
I played with this while you guys were talking about it. My suggestion was similar, kinda...
range=100 scale=5; w=$((${#range} scale));
printf "%0$w.${scale}f\n" "$((RANDOM%$range)).$(
s=$scale; while ((s--)); do printf "%s" $((RANDOM)); done
)"
I still think awk
is a much better solution, though.
CodePudding user response:
Follow working fine for me, based of the answer of markp-fuso and sample on my question, for positive counts (a not for negative counts), which give me equal distributed count with a asked count of decimal places, which can set by a var.
ug_rnd=0
og_rnd=10
decimal_places=2
decimal_places_faktor=$((10**decimal_places))
ug_rnd_new=$((ug_rnd*decimal_places_faktor))
og_rnd_new=$((og_rnd*decimal_places_faktor))
rnd="$((0x$(dd if=/dev/urandom of=/dev/stdout bs=4 count=1 status=none | xxd -p)))"
my_rnd=$((rnd%(og_rnd_new-ug_rnd_new 1) ug_rnd_new));
echo "$my_rnd"
printf -v my_new_rnd "%d.d" "$((my_rnd/decimal_places_faktor))" "$(($my_rnd