skip to Main Content

The question is related on Linux like Debian or Ubuntu, bash and a given function which use RANDOM.

Every improvement should use bash only.

Given are the follow function:

getRND(){
    min="${1:-1}"   ## min is the first parameter, or 1 if no parameter is given           
    max="${2:-100}" ## max is the second parameter, or 100 if no parameter is given
    rnd_count=$((RANDOM%(max-min+1)+min));
    echo "$rnd_count"
}

var=$(getRND -10 10) # Call the function
echo $var # output

How too:

  • Improve the randomness

The solution is sought for Linux systems on which no bash 5.1 is installed already and therefore no SRANDOM can be used up to now.

3

Answers


  1. Chosen as BEST ANSWER

    And this is how it looks when the code from the question and the code from KamilCuk's answer are combined in one function for doing the random more equally distributed:

    #!/bin/bash
    
    get_rnd_num_eq_dis(){
        min="${1:-1}"   # min is the first parameter, or 1 if no parameter is given           
        max="${2:-100}" # max is the second parameter, or 100 if no parameter is given
    #   rnd=$(srandom)
        srnd="$((0x$(dd if=/dev/urandom of=/dev/stdout bs=4 count=1 status=none | xxd -p)))"
        rnd_count=$((srnd%(max-min+1)+min));
        echo "$rnd_count"
    }
    
    var=$(get_rnd_num_eq_dis -100 100) # Call the function
    echo "$var" # output
    
    sleep 2
    

    Remark: Its looks like it can be used in a range bigger than +-32000


  2. making seed for RANDOM in main shell and expecting it to be favoured in subshell is pointless because new shell makes its own initialization of seed.

    so you need to seed and use RANDOM of main shell and pass value into another function for transformation.

    here is an example how to make your seed to work:

    #!/bin/bash
    
    
    normalize_value(){
        value_to_normalize=$1
        min="${2:-1}"   ## min is the first parameter, or 1 if no parameter is given           
        max="${3:-100}" ## max is the second parameter, or 100 if no parameter is given
        rnd_count=$((value_to_normalize % (max-min+1)+min));
        echo "$rnd_count"
    }
    
    RANDOM=$(date +%s%N | cut -b10-19)
    
    rnd=$RANDOM # get random value in a context of main shell and your seed
    var=$(normalize_value $rnd -10 10) # pass random value into normalizer function
    echo $var # output
    
    ###### following example will NOT WORK because statement refers to subshell's random generator
    RANDOM=1
    var=$(normalize_value $RANDOM -10 10) # wrong random sequence is used (not seeded by you)
    echo $var # output
    
    var=$(normalize_value $RANDOM -10 10) # wrong
    echo $var # output
    
    
    Login or Signup to reply.
  3. what can be improved on a given random function to make it more random or for a bigger range or something else?

    and therefore no SRANDOM can be used up to now.

    How to improve the randomness of the fuction above, if possible ?

    Sooo write your own SRANDOM with your own semantics. Ex:

    srandom() {
       # take random number from /dev/urandom
       # we take only just 4 bytes - one 2^32 number
       printf "%dn" "0x$(
           dd if=/dev/urandom of=/dev/stdout bs=4 count=1 status=none |
           xxd -p)"
    }
    

    and then:

    normalize_value(){
       ...
       rnd=$(srandom)
       rnd_count=$((rnd / ...))
    }
    

    Accepting a wider range of numbers

    If you are not happy with the way shell arithmetic expansion works, then… use a different tool. bc calculator has unlimited range.

    rnd_count=$(echo "
         # see https://superuser.com/questions/31445/gnu-bc-modulo-with-scale-other-than-0
         scale=0; 
         # super big random number from three 2^32 numbers
         rnd = $(srandom) * 2^(32*2) +  $(srandom) * 2^32 + $(srandom)
         rnd % ($max - $min + 1) + $min
         " | bc)
    

    You can write your own C program with getrandom() and compile it on the fly echo "int main() { stuff(); }" | gcc -xc - && ./a.out; rm ./a.out basically granting you any semantics you want. There are also other scripting languages, like perl, python, ruby, all most probably with their own big-number libraries and urandom number generation implementations. Sky the limit.

    Every improvement should use bash only.

    Is from my perspective a pointless limitation – overall, I am paid for results, not really "how" I solve problems. Anyway, you could, giving you a bunch of ideas how to proceed:

    • First write a function that would read from /dev/urandom and convert the bytes into a number.
      • I have no good idea how to do it in pure bash while keeping the randomness at sane levels. I suspect the input will drain fast.
      • You could read one byte from urandom. You’ll have to ignore read exit status, cause the byte may be zero byte or newline.
      • Then check if that byte is a digit. If it’s not, repeat previous step.
      • Treat such algorithm treat as a generator of random number within the range of 0-9. Build bigger numbers from those digits.
    • Then develop your own big-number library using arithmetic expansion as a "backend", written in bash.
      • Seems pretty pointless, because bc is commonly available.
      • This would work as usual big number libraries do.
      • I suggest to store the number as an array of number at max 2^16. For inspiration, research similar libraries written in C and C++ languages, and convert it to bash.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search