# How to achieve “continuos randomness”?

With `RANDOM%x`one gets a set of discrete results.

How can I achieve following scenario?: Inside a for loop, I'd like to let a bash script execute command A in 33.33% of all loops and else execute command B (66.66%).

• Why is modulo 3 not adequate? – Michael Homer Jul 9 '15 at 6:52
• What is `RANDOM%x`? I don't have this tool for shell scripts. And what do you mean by continuos? – ikrabbe Jul 9 '15 at 7:07
• Over how small (or large) a sample size do you want to guarantee 1:2 ratio of `A` and `B`? A random number generator could produce `AAA` over three runs; is this acceptable? If you require one `A` and two `B` values in every three runs, it's important to know this before formulating a solution. – roaima Jul 9 '15 at 15:20

You use `RANDOM` `%` `x`, just like you said.

``````if [[ \$((RANDOM % 3)) == 0 ]]
then
A
else
B
fi
``````

⅓ of the time the value modulo 3 will be 0, and then command A is executed. The rest of the time, command B is executed.

• Strictly speaking this is not a perfect 1/3 to 2/3 ratio. `RANDOM` generates values 0..32767 inclusive. Modulo 3 gives values in the range 0..2. However, if you modulo 32767 %3 you'll get 1, so values 0 and 1 will have a higher statistical occurrence than 2. (However, for many purposes this will be an insignificant error.) – roaima Jul 9 '15 at 15:14

For example, to get a decimal random number from the pseudo random number generator (prng) you can use

``````dd bs=1 count=1 if=/dev/urandom 2>/dev/null|od -i|awk '{print \$2}'
``````

As Michael proposed, you can use modulo 3 on this number, or you can just use

``````let b=`dd bs=1 count=1 if=/dev/urandom 2>/dev/null|od -i|awk '{print \$2}'`
if [ \$b -ge 85 ]
then B
else A
fi
``````

With this you have 33.33% <85 and 66.66% >= 85, so you branch on 85.

As I used `dc` (the polish reverse notation calculator) anyway you can of course just use the modulo

``````let b=`dd bs=1 count=1 if=/dev/urandom 2>/dev/null|od -t u1|awk '{print \$2" 3%pq"}'|dc`
if [ \$b -eq 0 ]
then A
else B
fi
``````
• Your first approach (random byte 0..255 less than 85) is approximately correct but your second is not. "To get a number range divisible by 3 you need 3 bytes" is not true. If you add three numbers each uniform random over 0..255 the sum is NOT uniform over 0..767 (or even 0..765, the actual range); the probability it is less-than 256 is only 16.86% and the best approximation to 33.33% is less-than 325. For a start on understanding why see math.stackexchange.com/a/431375 . – dave_thompson_085 Jul 9 '15 at 14:35
• Yes, you are right. It was early in the morning. I need two bytes and mask take only the next two bits from the upper one. But that makes it too complex. The modulo 3 version is the best anyway. – ikrabbe Jul 9 '15 at 14:38

You should not use a random number to get the desired 33% vs 66% results.

Just increase a counter and use the modulo 3 as mentioned by some others before:

``````#!/bin/bash

count=0 ca=0  cb=0
while ((count++)); ((count <100)); do
if [[ \$((\$count % 3)) == 0 ]]
then
((ca++))
else
((cb++))
fi
done
printf "count of ca: %d\ncount of cb: %d" \${ca} \${cb}
``````

This results in:

``````count of ca: 33
count of cb: 66
``````

When a randomizer is used the results are unexpected (not 33% vs 66%):

``````#with a changed if statement:
#if [[ \$((\$RANDOM % 3)) == 0 ]]
#the results of three runs are:
count of ca: 31
count of cb: 68

count of ca: 27
count of cb: 72

count of ca: 44
count of cb: 55
``````
• Your sample size was not large enough for the statistical flattening of 1/3 to 2/3. The output `AAA` is perfectly acceptable for a random number generator, as is `ABB` or even `BBB`. – roaima Jul 9 '15 at 15:16