Is it possible to generate real random numbers with a specific precision and in a specific range using the Integer Random Generator $RANDOM? For example how we can generate real number with 4 precision between 0 and 1?


A simple workaround:

printf "%d04.%d04\n" $RANDOM $RANDOM
  • 1
    Please specify what you mean by "real random numbers". Are you requiring a source of random numbers generated by something like particle decay, or will you be happy with a pseudo-random generator? Is your application of these numbers of cryptographic or scientific significance, or do you just want something that "looks random".
    – Kusalananda
    Feb 17, 2018 at 7:28
  • ... or do you actually mean "float" or "floating point number?
    – Kusalananda
    Feb 17, 2018 at 9:00
  • Thank you for comment. I need a pseudo random number generator for floating point numbers based on $RANDOM.
    – sci9
    Feb 17, 2018 at 10:29
  • ...for implementing meta heuristic algorithms in bash.
    – sci9
    Feb 17, 2018 at 10:30

6 Answers 6

awk -v n=10 -v seed="$RANDOM" 'BEGIN { srand(seed); for (i=0; i<n; ++i) printf("%.4f\n", rand()) }'

This will output n random numbers (ten in the example) in the range [0,1) with four decimal digits. It uses the rand() function in awk (not in standard awk but implemented by most common awk implementations) which returns a random value in that range. The random number generator is seeded by the shell's $RANDOM variable.

When an awk program only has BEGIN blocks (and no other code blocks), awk will not try to read input from its standard input stream.

On any OpenBSD system (or system that has the same jot utility, originally in 4.2BSD), the following will generate 10 random number as specified:

jot -p 4 -r 10 0 1
  • 1
    Really strictly speaking, since the output of rand() is a float within [0,1), it probably isn't exactly evenly distributed when rounded off to four decimal digits. It would be, if the float were of infinite precision, but it isn't: it's likely to be generated from random bits, so there are 2^N different values, and they don't map uniformly to a set of 1000 values. But as long as those pseudo-random floats have enough bits, and you're not doing anything really exact, you probably won't notice.
    – ilkkachu
    Aug 4, 2018 at 19:07

As pointed out in another answer, there are other utilities that you can use to generate random numbers. In this answer, I limit my resources to $RANDOM, and a few basic arithmetic functions.

For floating point numbers, try something like

printf '%s\n' $(echo "scale=8; $RANDOM/32768" | bc )

That will get you the best precision because $RANDOM only generates numbers between 0 and 32767. (including 32767!) But, I've also broken my rule about using basic arithmetic functions by invoking bc.

But before moving on, I'd like to look at two issues precision and range for floating point numbers. After that, I will look at generating a range of integers (and if you can generate integers, you can later divide them to get a decimal if you wish using whatever utilities you prefer to accomplish that.)


Taking the approach of $RANDOM/32768, since $RANDOM generates values from 0 to 32767, the result of $RANDOM/32768 will likewise be finitely many values. In other words, it's still a discrete random variable (and with a computer you'll never be able to get away from that fact). With that in mind, then you can accomplish some degree of precision by using printf.

If you want a finer covering of the interval, you could start thinking in base 32768. So, in theory $RANDOM + $RANDOM*32768 should give you a uniform distribution between 0 and 1,073,741,823. But, I'm doubtful the command line will handle that precision very well. A couple points relating to this particular case:

  • The sum of two independent, uniformly distributed random variables in not generally uniform. In this case, at least theoretically speaking (see third point), they are.
  • Don't think you can simplify $RANDOM + $RANDOM*32768 = $RANDOM * ( 1 + 32768 ). The two occurrences of $RANDOM are really two different events.
  • I don't know enough about how $RANDOM is generated to know whether calling it twice like this will truly generate two independent random events.


Let's consider just $RANDOM/32768. If you want a number in a range, say [a,b), then

$RANDOM/32768*(b-a) + a

will land you in the desired range.

Generation of integer values

First, consider generating random numbers between [0,b) where b is less than 32768. Consider the product q*b, where q is the integer part of 32768/b. Then what you can do is generate random number between 0 and 32767, but throw out those which are greater than or equal to q*b. Call the number thus generated G. Then G will fall in the range of 0 to q*b, and its distribution will be uniform. Now, apply modular arithmetic to get this value whittled down into the desired range:

G % b

Note, randomly generating a number as follows


will not create a uniform distribution, unless b just happens to be one of the divisors of 32768.

Writing a bash script for this

Calculating q*b as described above sounds like a pain. But it really isn't. You can get it as follows:

q*b = 32768 - ( 32768 % b )

In Bash, you can get this with

$((32768 - $((32768 % b)) ))

The following code will generate a random number in the range 0..b (not inclusive of b). b=$1

m=$((32768 - $((32768 % $1)) ))
while (( $a > $m )); 
a=$(($a % $1))
printf "$a\n"


Technically, there's little reason to work with

m=$((32768 - $((32768 % $1)) ))

The following will accomplish the same thing

while (( $a > $1 )); 
printf "$a\n"

It's a lot more work, but computers are fast.

Generating an Integer in a larger range

I'll let you figure this out. Care needs to be taken, and at some point you'll have to take into consideration the memory limitations of the computer in handling arithmetic operations.

Final note

The accepted answer will not create a random number uniformly over 0 to 1.

To see this, try the following

$ for i in {1..1000}; do echo .$RANDOM; done | awk '{ a += $1 } END { print a }'

For a truly uniform distribution over [0,1) you should be seeing an average of close to 0.500.

But as you can see by running the above snippet, you will instead get something like 314.432 or 322.619. Since it's 1000 numbers, the average of this is .322. The true average for this sequence of generated numbers is .316362

You can obtain this true average using the perl script

  perl -e '{ $i=0;  
             while ( $i<=32767 ) 
                 $j = sprintf "%.5f", ".$i"; 
                 $j =~ s/^0\.//; 
                 print "$j\n"; 
                 $s += $j; 
             printf "%.5f\n", $s/32767; 

I'm adding integers here to help you see how this approach of using .$RANDOM isn't doing what you most likely want it to do. In other words, think about which integers are being generated and which ones are missed altogether. Quite a large number are skipped; quite a few are doubled.


On systems where shell's printf is able to understand the %a format (bash ksh zsh , etc.) and therefore is able to perform an internal base change (hex -> dec) (uniform in [0,1) range from 0.00003 to 0.99997):

printf '%.5f\n' "$(printf '0x0.%04xp1' $RANDOM)"

You could even use more digits by combining more calls to $RANDOM (from 0.000000001 to 0.999999999)

printf '%.9f\n'  "$(printf '0x0.%08xp2' $(( ($RANDOM<<15) + $RANDOM )))"

The internal (to the shell) "$RANDOM" algorithm is based in a linear-feedback shift register (LFSR). Those are not Cryptographically Secure Pseudo Random Number Generators (CSPRNGs). A better option is to use bytes from the /dev/urandom device. That will require the call to external octal or hex dump.

$ printf '%.19f\n' "0x0.$(od -N 8 -An -tx1 /dev/urandom | tr -d ' ')"

$ printf '%.19f\n' "0x0.$(hexdump -n 8 -v -e '"%02x"' /dev/urandom)"

A very simple (but non-uniform) solution to get a float is:

printf '0.%04d\n' $RANDOM

A way to make it uniform in the range [0,1) (not including 1):

while a=$RANDOM; ((a>29999)); do :; done; printf '0.%04d\n' "$((a%10000))"

Use $(( ( RANDOM % N ) + MIN ))

Replace N with MAX number and MIN with minimum number you want to generate.(N as MAX is exclusive, put N+1 to have both MAX, MIN inclusive).

Or you can use $(shuf -i MIN-MAX -n 1) instead.

from 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

The -n 1 in shuf here means only generate one random Number.

This will generate random numbers between 0~9999 with leading zeros using printf (in result, number 1 is exclusive).

printf "0.%04d\n" $(( RANDOM % 1000 ))
  • 2
    This also will not produce a true random number in the given range except in the case where N is a divisor of 32767 (the upper limit of $RANDOM).
    – A.Ellett
    Aug 4, 2018 at 7:04

On bash

bc -l <<< "scale=4 ; $((RANDOM % 10000 ))/10000"

where 1/10000 is your random precision and 4 digits your output precision

  • When I re-run this I get the same answer over and over again. Any idea why that happens? If I just echo $RANDOM I get different results.
    – four43
    Jan 25, 2022 at 13:59
  • 1
    I'm retring now and it works for me
    – Andrea993
    Jan 26, 2022 at 14:09
  • Oh odd. I wonder if I accidentally assigned it or something. A fresh shell session works works.
    – four43
    Jan 31, 2022 at 16:34

zsh has a rand48() arithmetic function (wrapper to the erand48() standard function) in its zsh/mathfunc module:

zmodload zsh/mathfunc
printf '%.4f\n' $((rand48()))

While $RANDOM is 15 bits, pseudo-random and reproducible, bash 5.1+ has a safer 32 bit integer $SRANDOM, based on truly random sources where available. It doesn't support floating point arithmetic, but at least you can use it to seed awk's pseudo random generator (which otherwise by default uses the very predictable result of time()):

echo "$SRANDOM" | awk '
    for (i = 0; i < 20; i++)
      printf "%.4f\n", rand()

(bear in mind it's still only 32 bits of entropy, and awk does deterministic pseudo-random generation based on that seed)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .