1

[SOLVED]

I want to generate a uniform random float number in the range of float numbers in the bash script. range e.g. [3.556,6.563]

basically, I am creating LSH(Latin hypercube sampling) function in bash. There I would like to generate an array as one can do with this python command line.

p = np.random.uniform(low=l_lim, high=u_lim, size=[n]).

sample code :

lhs(){

    l_lim=($(seq $1 $2 $(echo $3 - $dif | bc)))
    h_lim=($(seq $(echo $1 + $dif | bc) $2 $3))
    points=()
    for ((i=0;i<$n;i++)) ; do 
        di=${l_lim[i]}
        dj=${h_lim[i]}
        echo $di, $dj
        p=$(awk -v min=6.50 -v max=8.45 -v seed=$RANDOM 'BEGIN{srand(seed);print min+rand()*int(1000*(max-min)+1)/1000}')
        points+=("${p}")
    done
    
}

n=5
a=(3 5)
b=(1 3)
dif=$(div $(echo ${a[1]} - ${a[0]} | bc) $n)

lhs ${a[0]} 0.45 ${a[1]}
echo ${points[@]}

I have tried $RANDOM, awk but it did not work for me. I do not want to use python -c.

Darshan
  • 71
  • 11
  • Please show us _how_ you tried to use awk, and exactly how it failed -- it's very much the best tool for the job. – Charles Duffy Nov 11 '20 at 16:32
  • By the way -- `export` should be only used when you have a specific reason to create an environment variable rather than a regular shell variable; and `array=( $(anything) )` is an antipattern; see [BashPitfalls #50](http://mywiki.wooledge.org/BashPitfalls#hosts.3D.28_.24.28aws_....29_.29). Consider making a habit of running your code through http://shellcheck.net/ before asking questions here. – Charles Duffy Nov 11 '20 at 16:33
  • ` would like to replicate the python command line .. np.random.uniform ..` I believe that is close to beeing too broad for a stackoverflow question. Or impossible, as I see in numpy sources, it manipulates in C source file internal float representation. That's not possible in bash. – KamilCuk Nov 11 '20 at 16:35
  • Yeah, @CharlesDuffy I have used it because I wanted to use `python -c` but I do not have a python package where I want to run script. So i understand that it is unnecessary. Thanks for remark. – Darshan Nov 11 '20 at 16:35
  • I asked for an example of how you tried to use awk, not how you tried to use Python. – Charles Duffy Nov 11 '20 at 16:36
  • 1
    @CharlesDuffy `$ awk -v min=$di -v max=$dj 'BEGIN{srand(); for (i=1;i<=num;i++) print min+rand()*int(1000*(max-min)+1)/1000}' ` but it generates same number every time. – Darshan Nov 11 '20 at 16:41
  • Okay, great. The problem there is one of needing to seed the RNG; that's easily fixed. Would you consider editing that awk code into the question? – Charles Duffy Nov 11 '20 at 16:42
  • ...not just "easily fixed", but it's a duplicate; see [random number generation with awk in bash shell](https://stackoverflow.com/questions/4048378/random-numbers-generation-with-awk-in-bash-shell) -- the approach of using the shell's `RANDOM` to seed awk's rng is exactly what I was going to suggest here. – Charles Duffy Nov 11 '20 at 16:43
  • See https://ideone.com/Zo97aO showing your above awk code corrected as described in the linked duplicate. – Charles Duffy Nov 11 '20 at 16:47
  • 1
    Thanks @CharlesDuffy It worked for me. Solution : `p=$(awk -v min=$di -v max=$dj -v seed=$RANDOM 'BEGIN{srand(seed);print min+rand()*int(1000*(max-min)+1)/1000}')` – Darshan Nov 11 '20 at 16:54
  • BTW, if you're going to need a lot of randomly-generated numbers in the same range, consider getting them all from one copy of awk, instead of restarting awk over and over. For example, you could run `exec {rng_fd}< <(awk ...)` with awk code that creates an infinite stream, then `read num <&$rng_fd` whenever you want another number from that stream, and `exec {rng_fd}<&-` to close the stream when you're done with it. – Charles Duffy Nov 11 '20 at 16:58

1 Answers1

0

Most common rand() implementations at least generate a number in the range [0...1), which is really all you need. You can scale a random number in one range to a number in another using the techniques outlined in the answers to this question, eg:

NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin

For bash you have two choices: integer arithmetic or use a different tool.

Some of your choices for tools that support float arithmetic from the command-line include:

  • a different shell (eg, zsh)
  • perl: my $x = $minimum + rand($maximum - $minimum);
  • ruby: x = min + rand * (max-min)
  • awk: awk -v min=3 -v max=17 'BEGIN{srand(); print min+rand()*int(1000*(max-min)+1)/1000}'
    note: The original answer this was copied from is broken; the above is a slight modification to help correct the problem.
  • bc: printf '%s\n' $(echo "scale=8; $RANDOM/32768" | bc )

... to name a few.

Brian Vandenberg
  • 4,011
  • 2
  • 37
  • 53
  • Note that the create -> insta-delete -> edit -> undelete workflow can constitute a rule violation when done for the purpose of circumventing site rules (explicitly inclusive of the "no answering deleted questions" rule). I'm looking for the recent [meta] discussion where this came up; will link it in when I find it. – Charles Duffy Nov 11 '20 at 16:53
  • Understood. I accidentally hit submit before I'd finished typing it up. It won't happen again. – Brian Vandenberg Nov 11 '20 at 16:54
  • ...ahh, here we are: [How long is the grace period for answering closed questions and why is it only applicable to some?](https://meta.stackoverflow.com/questions/402436/how-long-is-the-grace-period-for-answering-closed-questions-and-why-is-it-onl#comment805078_402450). Just an FYI, I'm not a diamond-moderator and can't enforce. – Charles Duffy Nov 11 '20 at 16:55
  • Thank you, I appreciate the heads up. When I un-deleted my answer I didn't see that you'd closed it. – Brian Vandenberg Nov 11 '20 at 16:55
  • @BrianVandenberg : Thank you for the answer, Ruby([e.g.](https://www.linuxquestions.org/questions/programming-9/random-float-numbers-in-bash-871336/#post4305628)), awk worked fine for me. – Darshan Nov 11 '20 at 16:58
  • 1
    @BrianVandenberg ```$ awk -v min=4 -v max=4.5 'BEGIN{srand(); print min+rand()*(max-min+1)}' $ 5.46869 ``` -> That is why (max-min + 1) will not work. – Darshan Nov 11 '20 at 17:13
  • @даршан I copied that example from [an answer to another question](https://stackoverflow.com/a/50359625/549246). I'm not in front of a machine I can test it on to correct it. – Brian Vandenberg Dec 02 '20 at 15:43
  • 1
    @BrianVandenberg I have tested and also edited your answer. – Darshan Dec 02 '20 at 15:48
  • 1
    @BrianVandenberg Look at the comment in the same answer that you suggested. – Darshan Dec 02 '20 at 15:50